langchainrb 0.6.3 → 0.6.4
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 +4 -4
- data/CHANGELOG.md +6 -0
- data/Gemfile.lock +1 -1
- data/examples/conversation_with_openai.rb +52 -0
- data/lib/langchain/conversation.rb +28 -36
- data/lib/langchain/conversation_memory.rb +88 -0
- data/lib/langchain/llm/base.rb +2 -0
- data/lib/langchain/llm/cohere.rb +1 -1
- data/lib/langchain/llm/openai.rb +1 -1
- data/lib/langchain/loader.rb +31 -8
- data/lib/langchain/utils/token_length/google_palm_validator.rb +3 -0
- data/lib/langchain/vectorsearch/base.rb +5 -0
- data/lib/langchain/vectorsearch/chroma.rb +11 -4
- data/lib/langchain/vectorsearch/hnswlib.rb +1 -2
- data/lib/langchain/vectorsearch/milvus.rb +11 -1
- data/lib/langchain/vectorsearch/pinecone.rb +6 -0
- data/lib/langchain/vectorsearch/qdrant.rb +10 -3
- data/lib/langchain/vectorsearch/weaviate.rb +6 -0
- data/lib/langchain/version.rb +1 -1
- data/lib/langchain.rb +1 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 78810f63a496c6b98208a9c838cbdae41a8c944879e68f16fc4362de90c49110
|
4
|
+
data.tar.gz: c95d357da62c8120a2a105a94b219ca1f3552f85fff30bb7cb3d40def336baeb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ee0c549ecebd98ce940b6dc05c8aa2783c265d7cb3903ca30448be0f906e89f353e419b2bb862178fe9081baa002b42fd7aaf88ec244a63beec9bc862e3a9410
|
7
|
+
data.tar.gz: a4b67c5b0d268d6b96622209fe3201c8585bf44d1d44dca0bc061de3f1ba1797e87df61111ddc6565b0d75b23a06677aa3bad6e41fbd4a119ff69f6b11e756ee
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.6.4] - 2023-07-01
|
4
|
+
- Fix `Langchain::Vectorsearch::Qdrant#add_texts()`
|
5
|
+
- Introduce `ConversationMemory`
|
6
|
+
- Allow loading multiple files from a directory
|
7
|
+
- Add `get_default_schema()`, `create_default_schema()`, `destroy_default_schema()` missing methods to `Langchain::Vectorsearch::*` classes
|
8
|
+
|
3
9
|
## [0.6.3] - 2023-06-25
|
4
10
|
- Add #destroy_default_schema() to Langchain::Vectorsearch::* classes
|
5
11
|
|
data/Gemfile.lock
CHANGED
@@ -0,0 +1,52 @@
|
|
1
|
+
require "langchain"
|
2
|
+
require "reline"
|
3
|
+
|
4
|
+
# gem install reline
|
5
|
+
# or add `gem "reline"` to your Gemfile
|
6
|
+
|
7
|
+
openai = Langchain::LLM::OpenAI.new(api_key: ENV["OPENAI_API_KEY"])
|
8
|
+
|
9
|
+
chat = Langchain::Conversation.new(llm: openai)
|
10
|
+
chat.set_context("You are a chatbot from the future")
|
11
|
+
|
12
|
+
DONE = %w[done end eof exit].freeze
|
13
|
+
|
14
|
+
puts "Welcome to the chatbot from the future!"
|
15
|
+
|
16
|
+
def prompt_for_message
|
17
|
+
puts "(multiline input; type 'end' on its own line when done. or exit to exit)"
|
18
|
+
|
19
|
+
user_message = Reline.readmultiline("Question: ", true) do |multiline_input|
|
20
|
+
last = multiline_input.split.last
|
21
|
+
DONE.include?(last)
|
22
|
+
end
|
23
|
+
|
24
|
+
return :noop unless user_message
|
25
|
+
|
26
|
+
lines = user_message.split("\n")
|
27
|
+
if lines.size > 1 && DONE.include?(lines.last)
|
28
|
+
# remove the "done" from the message
|
29
|
+
user_message = lines[0..-2].join("\n")
|
30
|
+
end
|
31
|
+
|
32
|
+
return :exit if DONE.include?(user_message.downcase)
|
33
|
+
|
34
|
+
user_message
|
35
|
+
end
|
36
|
+
|
37
|
+
begin
|
38
|
+
loop do
|
39
|
+
user_message = prompt_for_message
|
40
|
+
|
41
|
+
case user_message
|
42
|
+
when :noop
|
43
|
+
next
|
44
|
+
when :exit
|
45
|
+
break
|
46
|
+
end
|
47
|
+
|
48
|
+
puts chat.message(user_message)
|
49
|
+
end
|
50
|
+
rescue Interrupt
|
51
|
+
exit 0
|
52
|
+
end
|
@@ -17,10 +17,7 @@ module Langchain
|
|
17
17
|
# end
|
18
18
|
#
|
19
19
|
class Conversation
|
20
|
-
attr_reader :
|
21
|
-
|
22
|
-
# The least number of tokens we want to be under the limit by
|
23
|
-
TOKEN_LEEWAY = 20
|
20
|
+
attr_reader :options
|
24
21
|
|
25
22
|
# Intialize Conversation with a LLM
|
26
23
|
#
|
@@ -31,7 +28,11 @@ module Langchain
|
|
31
28
|
@llm = llm
|
32
29
|
@context = nil
|
33
30
|
@examples = []
|
34
|
-
@
|
31
|
+
@memory = ConversationMemory.new(
|
32
|
+
llm: llm,
|
33
|
+
messages: options.delete(:messages) || [],
|
34
|
+
strategy: options.delete(:memory_strategy)
|
35
|
+
)
|
35
36
|
@options = options
|
36
37
|
@block = block
|
37
38
|
end
|
@@ -39,59 +40,50 @@ module Langchain
|
|
39
40
|
# Set the context of the conversation. Usually used to set the model's persona.
|
40
41
|
# @param message [String] The context of the conversation
|
41
42
|
def set_context(message)
|
42
|
-
@
|
43
|
+
@memory.set_context message
|
43
44
|
end
|
44
45
|
|
45
46
|
# Add examples to the conversation. Used to give the model a sense of the conversation.
|
46
47
|
# @param examples [Array<Hash>] The examples to add to the conversation
|
47
48
|
def add_examples(examples)
|
48
|
-
@
|
49
|
+
@memory.add_examples examples
|
49
50
|
end
|
50
51
|
|
51
52
|
# Message the model with a prompt and return the response.
|
52
53
|
# @param message [String] The prompt to message the model with
|
53
54
|
# @return [String] The response from the model
|
54
55
|
def message(message)
|
55
|
-
append_user_message(message)
|
56
|
+
@memory.append_user_message(message)
|
56
57
|
response = llm_response(message)
|
57
|
-
append_ai_message(response)
|
58
|
+
@memory.append_ai_message(response)
|
58
59
|
response
|
59
60
|
end
|
60
61
|
|
61
|
-
|
62
|
-
|
63
|
-
def
|
64
|
-
@
|
65
|
-
rescue Langchain::Utils::TokenLength::TokenLimitExceeded => exception
|
66
|
-
raise exception if @messages.size == 1
|
67
|
-
|
68
|
-
reduce_messages(exception.token_overflow)
|
69
|
-
retry
|
62
|
+
# Messages from conversation memory
|
63
|
+
# @return [Array<Hash>] The messages from the conversation memory
|
64
|
+
def messages
|
65
|
+
@memory.messages
|
70
66
|
end
|
71
67
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
proceed
|
78
|
-
end
|
68
|
+
# Context from conversation memory
|
69
|
+
# @return [String] Context from conversation memory
|
70
|
+
def context
|
71
|
+
@memory.context
|
79
72
|
end
|
80
73
|
|
81
|
-
|
82
|
-
|
74
|
+
# Examples from conversation memory
|
75
|
+
# @return [Array<Hash>] Examples from the conversation memory
|
76
|
+
def examples
|
77
|
+
@memory.examples
|
83
78
|
end
|
84
79
|
|
85
|
-
|
86
|
-
@messages << {role: "user", content: message}
|
87
|
-
end
|
88
|
-
|
89
|
-
def model_name
|
90
|
-
@options[:model] || @llm.class::DEFAULTS[:chat_completion_model_name]
|
91
|
-
end
|
80
|
+
private
|
92
81
|
|
93
|
-
def
|
94
|
-
@llm.
|
82
|
+
def llm_response(prompt)
|
83
|
+
@llm.chat(messages: @memory.messages, context: @memory.context, examples: @memory.examples, **@options, &@block)
|
84
|
+
rescue Langchain::Utils::TokenLength::TokenLimitExceeded => exception
|
85
|
+
@memory.reduce_messages(exception)
|
86
|
+
retry
|
95
87
|
end
|
96
88
|
end
|
97
89
|
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Langchain
|
4
|
+
class ConversationMemory
|
5
|
+
attr_reader :examples, :messages
|
6
|
+
|
7
|
+
# The least number of tokens we want to be under the limit by
|
8
|
+
TOKEN_LEEWAY = 20
|
9
|
+
|
10
|
+
def initialize(llm:, messages: [], **options)
|
11
|
+
@llm = llm
|
12
|
+
@context = nil
|
13
|
+
@summary = nil
|
14
|
+
@examples = []
|
15
|
+
@messages = messages
|
16
|
+
@strategy = options.delete(:strategy) || :truncate
|
17
|
+
@options = options
|
18
|
+
end
|
19
|
+
|
20
|
+
def set_context(message)
|
21
|
+
@context = message
|
22
|
+
end
|
23
|
+
|
24
|
+
def add_examples(examples)
|
25
|
+
@examples.concat examples
|
26
|
+
end
|
27
|
+
|
28
|
+
def append_ai_message(message)
|
29
|
+
@messages << {role: "ai", content: message}
|
30
|
+
end
|
31
|
+
|
32
|
+
def append_user_message(message)
|
33
|
+
@messages << {role: "user", content: message}
|
34
|
+
end
|
35
|
+
|
36
|
+
def reduce_messages(exception)
|
37
|
+
case @strategy
|
38
|
+
when :truncate
|
39
|
+
truncate_messages(exception)
|
40
|
+
when :summarize
|
41
|
+
summarize_messages
|
42
|
+
else
|
43
|
+
raise "Unknown strategy: #{@options[:strategy]}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def context
|
48
|
+
return if @context.nil? && @summary.nil?
|
49
|
+
|
50
|
+
[@context, @summary].compact.join("\n")
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def truncate_messages(exception)
|
56
|
+
raise exception if @messages.size == 1
|
57
|
+
|
58
|
+
token_overflow = exception.token_overflow
|
59
|
+
|
60
|
+
@messages = @messages.drop_while do |message|
|
61
|
+
proceed = token_overflow > -TOKEN_LEEWAY
|
62
|
+
token_overflow -= token_length(message.to_json, model_name, llm: @llm)
|
63
|
+
|
64
|
+
proceed
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def summarize_messages
|
69
|
+
history = [@summary, @messages.to_json].compact.join("\n")
|
70
|
+
partitions = [history[0, history.size / 2], history[history.size / 2, history.size]]
|
71
|
+
|
72
|
+
@summary = partitions.map { |messages| @llm.summarize(text: messages.to_json) }.join("\n")
|
73
|
+
|
74
|
+
@messages = [@messages.last]
|
75
|
+
end
|
76
|
+
|
77
|
+
def partition_messages
|
78
|
+
end
|
79
|
+
|
80
|
+
def model_name
|
81
|
+
@llm.class::DEFAULTS[:chat_completion_model_name]
|
82
|
+
end
|
83
|
+
|
84
|
+
def token_length(content, model_name, options)
|
85
|
+
@llm.class::LENGTH_VALIDATOR.token_length(content, model_name, options)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
data/lib/langchain/llm/base.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Langchain::LLM
|
4
|
+
class ApiError < StandardError; end
|
5
|
+
|
4
6
|
# A LLM is a language model consisting of a neural network with many parameters (typically billions of weights or more), trained on large quantities of unlabeled text using self-supervised learning or semi-supervised learning.
|
5
7
|
#
|
6
8
|
# Langchain.rb provides a common interface to interact with all supported LLMs:
|
data/lib/langchain/llm/cohere.rb
CHANGED
data/lib/langchain/llm/openai.rb
CHANGED
@@ -125,7 +125,7 @@ module Langchain::LLM
|
|
125
125
|
|
126
126
|
response = client.chat(parameters: parameters)
|
127
127
|
|
128
|
-
raise "Chat completion failed: #{response}" if !response.empty? && response.dig("error")
|
128
|
+
raise Langchain::LLM::ApiError.new "Chat completion failed: #{response.dig("error", "message")}" if !response.empty? && response.dig("error")
|
129
129
|
|
130
130
|
unless streaming
|
131
131
|
response.dig("choices", 0, "message", "content")
|
data/lib/langchain/loader.rb
CHANGED
@@ -51,6 +51,13 @@ module Langchain
|
|
51
51
|
!!(@path =~ URI_REGEX)
|
52
52
|
end
|
53
53
|
|
54
|
+
# Is the path a directory
|
55
|
+
#
|
56
|
+
# @return [Boolean] true if path is a directory
|
57
|
+
def directory?
|
58
|
+
File.directory?(@path)
|
59
|
+
end
|
60
|
+
|
54
61
|
# Load data from a file or URL
|
55
62
|
#
|
56
63
|
# loader = Langchain::Loader.new("README.md")
|
@@ -69,15 +76,10 @@ module Langchain
|
|
69
76
|
#
|
70
77
|
# @return [Data] data that was loaded
|
71
78
|
def load(&block)
|
72
|
-
|
79
|
+
return process_data(load_from_url, &block) if url?
|
80
|
+
return load_from_directory(&block) if directory?
|
73
81
|
|
74
|
-
|
75
|
-
yield @raw_data.read, @options
|
76
|
-
else
|
77
|
-
processor_klass.new(@options).parse(@raw_data)
|
78
|
-
end
|
79
|
-
|
80
|
-
Langchain::Data.new(data, source: @path)
|
82
|
+
process_data(load_from_path, &block)
|
81
83
|
end
|
82
84
|
|
83
85
|
private
|
@@ -92,6 +94,27 @@ module Langchain
|
|
92
94
|
File.open(@path)
|
93
95
|
end
|
94
96
|
|
97
|
+
def load_from_directory(&block)
|
98
|
+
Dir.glob(File.join(@path, "**/*")).map do |file|
|
99
|
+
# Only load and add to result files with supported extensions
|
100
|
+
Langchain::Loader.new(file, @options).load(&block)
|
101
|
+
rescue
|
102
|
+
UnknownFormatError nil
|
103
|
+
end.flatten.compact
|
104
|
+
end
|
105
|
+
|
106
|
+
def process_data(data, &block)
|
107
|
+
@raw_data = data
|
108
|
+
|
109
|
+
result = if block
|
110
|
+
yield @raw_data.read, @options
|
111
|
+
else
|
112
|
+
processor_klass.new(@options).parse(@raw_data)
|
113
|
+
end
|
114
|
+
|
115
|
+
Langchain::Data.new(result)
|
116
|
+
end
|
117
|
+
|
95
118
|
def processor_klass
|
96
119
|
raise UnknownFormatError unless (kind = find_processor)
|
97
120
|
|
@@ -37,6 +37,9 @@ module Langchain
|
|
37
37
|
#
|
38
38
|
def self.token_length(text, model_name = "chat-bison-001", options)
|
39
39
|
response = options[:llm].client.count_message_tokens(model: model_name, prompt: text)
|
40
|
+
|
41
|
+
raise Langchain::LLM::ApiError.new(response["error"]["message"]) unless response["error"].nil?
|
42
|
+
|
40
43
|
response.dig("tokenCount")
|
41
44
|
end
|
42
45
|
|
@@ -98,6 +98,11 @@ module Langchain::Vectorsearch
|
|
98
98
|
@llm = llm
|
99
99
|
end
|
100
100
|
|
101
|
+
# Method supported by Vectorsearch DB to retrieve a default schema
|
102
|
+
def get_default_schema
|
103
|
+
raise NotImplementedError, "#{self.class.name} does not support retrieving a default schema"
|
104
|
+
end
|
105
|
+
|
101
106
|
# Method supported by Vectorsearch DB to create a default schema
|
102
107
|
def create_default_schema
|
103
108
|
raise NotImplementedError, "#{self.class.name} does not support creating a default schema"
|
@@ -67,10 +67,17 @@ module Langchain::Vectorsearch
|
|
67
67
|
::Chroma::Resources::Collection.create(index_name)
|
68
68
|
end
|
69
69
|
|
70
|
-
#
|
71
|
-
#
|
72
|
-
|
73
|
-
|
70
|
+
# Get the default schema
|
71
|
+
# @return [Hash] The response from the server
|
72
|
+
def get_default_schema
|
73
|
+
::Chroma::Resources::Collection.get(index_name)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Delete the default schema
|
77
|
+
# @return [Hash] The response from the server
|
78
|
+
def destroy_default_schema
|
79
|
+
::Chroma::Resources::Collection.delete(index_name)
|
80
|
+
end
|
74
81
|
|
75
82
|
# Search for similar texts
|
76
83
|
# @param query [String] The text to search for
|
@@ -10,8 +10,7 @@ module Langchain::Vectorsearch
|
|
10
10
|
# gem "hnswlib", "~> 0.8.1"
|
11
11
|
#
|
12
12
|
# Usage:
|
13
|
-
# hnsw = Langchain::Vectorsearch::Hnswlib.new(llm:,
|
14
|
-
#
|
13
|
+
# hnsw = Langchain::Vectorsearch::Hnswlib.new(llm:, path_to_index:)
|
15
14
|
|
16
15
|
attr_reader :client, :path_to_index
|
17
16
|
|
@@ -79,7 +79,17 @@ module Langchain::Vectorsearch
|
|
79
79
|
)
|
80
80
|
end
|
81
81
|
|
82
|
-
#
|
82
|
+
# Get the default schema
|
83
|
+
# @return [Hash] The response from the server
|
84
|
+
def get_default_schema
|
85
|
+
client.collections.get(collection_name: index_name)
|
86
|
+
end
|
87
|
+
|
88
|
+
# Delete default schema
|
89
|
+
# @return [Hash] The response from the server
|
90
|
+
def destroy_default_schema
|
91
|
+
client.collections.delete(collection_name: index_name)
|
92
|
+
end
|
83
93
|
|
84
94
|
def similarity_search(query:, k: 4)
|
85
95
|
embedding = llm.embed(text: query)
|
@@ -85,6 +85,12 @@ module Langchain::Vectorsearch
|
|
85
85
|
client.delete_index(index_name)
|
86
86
|
end
|
87
87
|
|
88
|
+
# Get the default schema
|
89
|
+
# @return [Pinecone::Vector] The default schema
|
90
|
+
def get_default_schema
|
91
|
+
index
|
92
|
+
end
|
93
|
+
|
88
94
|
# Search for similar texts
|
89
95
|
# @param query [String] The text to search for
|
90
96
|
# @param k [Integer] The number of results to return
|
@@ -32,11 +32,12 @@ module Langchain::Vectorsearch
|
|
32
32
|
# Add a list of texts to the index
|
33
33
|
# @param texts [Array] The list of texts to add
|
34
34
|
# @return [Hash] The response from the server
|
35
|
-
def add_texts(texts:, ids:)
|
35
|
+
def add_texts(texts:, ids: [])
|
36
36
|
batch = {ids: [], vectors: [], payloads: []}
|
37
37
|
|
38
38
|
Array(texts).each_with_index do |text, i|
|
39
|
-
|
39
|
+
id = ids[i] || SecureRandom.uuid
|
40
|
+
batch[:ids].push(id)
|
40
41
|
batch[:vectors].push(llm.embed(text: text))
|
41
42
|
batch[:payloads].push({content: text})
|
42
43
|
end
|
@@ -51,6 +52,12 @@ module Langchain::Vectorsearch
|
|
51
52
|
add_texts(texts: texts, ids: ids)
|
52
53
|
end
|
53
54
|
|
55
|
+
# Get the default schema
|
56
|
+
# @return [Hash] The response from the server
|
57
|
+
def get_default_schema
|
58
|
+
client.collections.get(collection_name: index_name)
|
59
|
+
end
|
60
|
+
|
54
61
|
# Deletes the default schema
|
55
62
|
# @return [Hash] The response from the server
|
56
63
|
def destroy_default_schema
|
@@ -109,7 +116,7 @@ module Langchain::Vectorsearch
|
|
109
116
|
def ask(question:)
|
110
117
|
search_results = similarity_search(query: question)
|
111
118
|
|
112
|
-
context = search_results.
|
119
|
+
context = search_results.map do |result|
|
113
120
|
result.dig("payload").to_s
|
114
121
|
end
|
115
122
|
context = context.join("\n---\n")
|
@@ -85,6 +85,12 @@ module Langchain::Vectorsearch
|
|
85
85
|
)
|
86
86
|
end
|
87
87
|
|
88
|
+
# Get default schema
|
89
|
+
# @return [Hash] The response from the server
|
90
|
+
def get_default_schema
|
91
|
+
client.schema.get(class_name: index_name)
|
92
|
+
end
|
93
|
+
|
88
94
|
# Delete the index
|
89
95
|
# @return [Boolean] Whether the index was deleted
|
90
96
|
def destroy_default_schema
|
data/lib/langchain/version.rb
CHANGED
data/lib/langchain.rb
CHANGED
@@ -51,6 +51,7 @@ module Langchain
|
|
51
51
|
autoload :Loader, "langchain/loader"
|
52
52
|
autoload :Data, "langchain/data"
|
53
53
|
autoload :Conversation, "langchain/conversation"
|
54
|
+
autoload :ConversationMemory, "langchain/conversation_memory"
|
54
55
|
autoload :DependencyHelper, "langchain/dependency_helper"
|
55
56
|
autoload :ContextualLogger, "langchain/contextual_logger"
|
56
57
|
|
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.6.
|
4
|
+
version: 0.6.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrei Bondarev
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-07-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: baran
|
@@ -474,6 +474,7 @@ files:
|
|
474
474
|
- LICENSE.txt
|
475
475
|
- README.md
|
476
476
|
- Rakefile
|
477
|
+
- examples/conversation_with_openai.rb
|
477
478
|
- examples/create_and_manage_few_shot_prompt_templates.rb
|
478
479
|
- examples/create_and_manage_prompt_templates.rb
|
479
480
|
- examples/create_and_manage_prompt_templates_using_structured_output_parser.rb
|
@@ -494,6 +495,7 @@ files:
|
|
494
495
|
- lib/langchain/chunker/text.rb
|
495
496
|
- lib/langchain/contextual_logger.rb
|
496
497
|
- lib/langchain/conversation.rb
|
498
|
+
- lib/langchain/conversation_memory.rb
|
497
499
|
- lib/langchain/data.rb
|
498
500
|
- lib/langchain/dependency_helper.rb
|
499
501
|
- lib/langchain/llm/ai21.rb
|