langchainrb 0.15.4 → 0.15.5

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: 68d2d64fb264bf47488e83581540b88f7746f0e1b1b318d7dfc9c15356f40c8c
4
- data.tar.gz: efbd840632f0f22b202d9257a2020c4bc49cea7528d79efa7e05f963e9e4745f
3
+ metadata.gz: cb478a5261da82b78d6a90b6179e4050ae0fcba274c370b507f546b59cfd1a78
4
+ data.tar.gz: 7fb27d8b3c68060e923e69b1c67680be20846e5a384def4c6ce0efd1c9fa56ab
5
5
  SHA512:
6
- metadata.gz: f57817cc62de3af8f9aa80c62e421255e4172f55d54d91c1adc7d7a03ac9272e866670532c996a19d502c6d3110627d778efdad8c4faad0b07868c8b0aebc81c
7
- data.tar.gz: b35d82314edc0d747c87a37bd0e2036755f884e85977639e8b53063ca8ebd7002b9dd4ae9a5dd443f088552e575471e080dc9aa4519e25efaa908e16130b613a
6
+ metadata.gz: b6533a4064e822c78cc7659c55c948b13b4904d75ab99fb50269f82d7f815e02ff3c0659f0b6c1905b16c0834f2577ccd136cb3d1a34db6e26b7352c77350a10
7
+ data.tar.gz: 170e767e0fdef21fc6051a161904ee867205bb18a98641b545adf7fe3933b499d157be52009fd20e168efa5d94e5a03c39a1a21c94c2747b8e6a0393f2099e4e
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.15.4] - 2024-09-10 🇧🇦
4
+ - Fix for Langchain::Prompt::PromptTemplate supporting nested JSON data
5
+ - Require common libs at top-level
6
+ - Add `add_message_callback` to `Langchain::Assistant` constructor to invoke an optional function when any message is added to the conversation
7
+ - Adding Assistant syntactic sugar with #run! and #add_message_and_run!
8
+
3
9
  ## [0.15.4] - 2024-08-30
4
10
  - Improve the Langchain::Tool::Database tool
5
11
  - Allow explictly setting tool_choice on the Assistant instance
data/README.md CHANGED
@@ -427,7 +427,7 @@ assistant.add_message_and_run(content: "What's the latest news about AI?")
427
427
  messages = assistant.messages
428
428
 
429
429
  # Run the assistant with automatic tool execution
430
- assistant.run(auto_tool_execution: true)
430
+ assistant.run!
431
431
  ```
432
432
 
433
433
  ### Configuration
@@ -435,11 +435,12 @@ assistant.run(auto_tool_execution: true)
435
435
  * `tools`: An array of tool instances (optional)
436
436
  * `instructions`: System instructions for the assistant (optional)
437
437
  * `tool_choice`: Specifies how tools should be selected. Default: "auto". A specific tool function name can be passed. This will force the Assistant to **always** use this function.
438
+ * `add_message_callback`: A callback function (proc, lambda) that is called when any message is added to the conversation (optional)
438
439
 
439
440
  ### Key Methods
440
441
  * `add_message`: Adds a user message to the messages array
441
- * `run`: Processes the conversation and generates responses
442
- * `add_message_and_run`: Combines adding a message and running the assistant
442
+ * `run!`: Processes the conversation and generates responses
443
+ * `add_message_and_run!`: Combines adding a message and running the assistant
443
444
  * `submit_tool_output`: Manually submit output to a tool call
444
445
  * `messages`: Returns a list of ongoing messages
445
446
 
@@ -30,7 +30,8 @@ module Langchain
30
30
  thread: nil,
31
31
  tools: [],
32
32
  instructions: nil,
33
- tool_choice: "auto"
33
+ tool_choice: "auto",
34
+ add_message_callback: nil
34
35
  )
35
36
  unless tools.is_a?(Array) && tools.all? { |tool| tool.class.singleton_class.included_modules.include?(Langchain::ToolDefinition) }
36
37
  raise ArgumentError, "Tools must be an array of objects extending Langchain::ToolDefinition"
@@ -38,7 +39,10 @@ module Langchain
38
39
 
39
40
  @llm = llm
40
41
  @llm_adapter = LLM::Adapter.build(llm)
42
+
41
43
  @thread = thread || Langchain::Thread.new
44
+ @thread.add_message_callback = add_message_callback
45
+
42
46
  @tools = tools
43
47
  self.tool_choice = tool_choice
44
48
  @instructions = instructions
@@ -51,9 +55,8 @@ module Langchain
51
55
  raise ArgumentError, "Thread must be an instance of Langchain::Thread" unless @thread.is_a?(Langchain::Thread)
52
56
 
53
57
  # The first message in the thread should be the system instructions
54
- # TODO: What if the user added old messages and the system instructions are already in there? Should this overwrite the existing instructions?
55
- initialize_instructions
56
58
  # For Google Gemini, and Anthropic system instructions are added to the `system:` param in the `chat` method
59
+ initialize_instructions
57
60
  end
58
61
 
59
62
  # Add a user message to the thread
@@ -107,6 +110,13 @@ module Langchain
107
110
  thread.messages
108
111
  end
109
112
 
113
+ # Run the assistant with automatic tool execution
114
+ #
115
+ # @return [Array<Langchain::Message>] The messages in the thread
116
+ def run!
117
+ run(auto_tool_execution: true)
118
+ end
119
+
110
120
  # Add a user message to the thread and run the assistant
111
121
  #
112
122
  # @param content [String] The content of the message
@@ -117,6 +127,14 @@ module Langchain
117
127
  run(auto_tool_execution: auto_tool_execution)
118
128
  end
119
129
 
130
+ # Add a user message to the thread and run the assistant with automatic tool execution
131
+ #
132
+ # @param content [String] The content of the message
133
+ # @return [Array<Langchain::Message>] The messages in the thread
134
+ def add_message_and_run!(content:)
135
+ add_message_and_run(content: content, auto_tool_execution: true)
136
+ end
137
+
120
138
  # Submit tool output to the thread
121
139
  #
122
140
  # @param tool_call_id [String] The ID of the tool call to submit output for
@@ -287,7 +305,7 @@ module Langchain
287
305
 
288
306
  def initialize_instructions
289
307
  if llm.is_a?(Langchain::LLM::OpenAI) || llm.is_a?(Langchain::LLM::MistralAI)
290
- add_message(role: "system", content: instructions) if instructions
308
+ self.instructions = @instructions if @instructions
291
309
  end
292
310
  end
293
311
 
@@ -4,12 +4,14 @@ module Langchain
4
4
  # Langchain::Thread keeps track of messages in a conversation.
5
5
  # TODO: Add functionality to persist to the thread to disk, DB, storage, etc.
6
6
  class Thread
7
- attr_accessor :messages
7
+ attr_accessor :messages, :add_message_callback
8
8
 
9
9
  # @param messages [Array<Langchain::Message>]
10
- def initialize(messages: [])
10
+ # @param add_message_callback [Proc] A callback to call when a message is added to the thread
11
+ def initialize(messages: [], add_message_callback: nil)
11
12
  raise ArgumentError, "messages array must only contain Langchain::Message instance(s)" unless messages.is_a?(Array) && messages.all? { |m| m.is_a?(Langchain::Messages::Base) }
12
13
 
14
+ @add_message_callback = add_message_callback
13
15
  @messages = messages
14
16
  end
15
17
 
@@ -34,6 +36,9 @@ module Langchain
34
36
  def add_message(message)
35
37
  raise ArgumentError, "message must be a Langchain::Message instance" unless message.is_a?(Langchain::Messages::Base)
36
38
 
39
+ # Call the callback with the message
40
+ add_message_callback.call(message) if add_message_callback # rubocop:disable Style/SafeNavigation
41
+
37
42
  # Prepend the message to the thread
38
43
  messages << message
39
44
  end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "json"
4
3
  require "json-schema"
5
4
 
6
5
  module Langchain::OutputParsers
@@ -1,4 +1,4 @@
1
- require "uri"
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Langchain
4
4
  module Processors
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "strscan"
4
- require "json"
5
4
  require "yaml"
6
5
 
7
6
  module Langchain::Prompt
@@ -2,7 +2,6 @@
2
2
 
3
3
  require "strscan"
4
4
  require "pathname"
5
- require "json"
6
5
  require "yaml"
7
6
 
8
7
  module Langchain::Prompt
@@ -58,8 +58,9 @@ module Langchain::Prompt
58
58
  #
59
59
  def format(**kwargs)
60
60
  result = @template
61
+ result = result.gsub(/{{/, "{").gsub(/}}/, "}")
61
62
  kwargs.each { |key, value| result = result.gsub(/\{#{key}\}/, value.to_s) }
62
- result.gsub(/{{/, "{").gsub(/}}/, "}")
63
+ result
63
64
  end
64
65
 
65
66
  #
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "json"
4
-
5
3
  #
6
4
  # Extends a class to be used as a tool in the assistant.
7
5
  # A tool is a collection of functions (methods) used to perform specific tasks.
@@ -42,8 +40,8 @@ module Langchain::ToolDefinition
42
40
  # @param method_name [Symbol] Name of the method to define
43
41
  # @param description [String] Description of the function
44
42
  # @yield Block that defines the parameters for the function
45
- def define_function(method_name, description:, &)
46
- function_schemas.add_function(method_name:, description:, &)
43
+ def define_function(method_name, description:, &block)
44
+ function_schemas.add_function(method_name:, description:, &block)
47
45
  end
48
46
 
49
47
  # Returns the FunctionSchemas instance for this tool
@@ -76,11 +74,11 @@ module Langchain::ToolDefinition
76
74
  # @param description [String] Description of the function
77
75
  # @yield Block that defines the parameters for the function
78
76
  # @raise [ArgumentError] If a block is defined and no parameters are specified for the function
79
- def add_function(method_name:, description:, &)
77
+ def add_function(method_name:, description:, &block)
80
78
  name = "#{@tool_name}__#{method_name}"
81
79
 
82
- if block_given?
83
- parameters = ParameterBuilder.new(parent_type: "object").build(&)
80
+ if block_given? # rubocop:disable Performance/BlockGivenWithExplicitBlock
81
+ parameters = ParameterBuilder.new(parent_type: "object").build(&block)
84
82
 
85
83
  if parameters[:properties].empty?
86
84
  raise ArgumentError, "Function parameters must have at least one property defined within it, if a block is provided"
@@ -130,8 +128,8 @@ module Langchain::ToolDefinition
130
128
  #
131
129
  # @yield Block that defines the properties of the schema
132
130
  # @return [Hash] The built schema
133
- def build(&)
134
- instance_eval(&)
131
+ def build(&block)
132
+ instance_eval(&block)
135
133
  @schema
136
134
  end
137
135
 
@@ -144,13 +142,13 @@ module Langchain::ToolDefinition
144
142
  # @param required [Boolean] Whether the property is required
145
143
  # @yield [Block] Block for nested properties (only for object and array types)
146
144
  # @raise [ArgumentError] If any parameter is invalid
147
- def property(name = nil, type:, description: nil, enum: nil, required: false, &)
145
+ def property(name = nil, type:, description: nil, enum: nil, required: false, &block)
148
146
  validate_parameters(name:, type:, enum:, required:)
149
147
 
150
148
  prop = {type:, description:, enum:}.compact
151
149
 
152
- if block_given?
153
- nested_schema = ParameterBuilder.new(parent_type: type).build(&)
150
+ if block_given? # rubocop:disable Performance/BlockGivenWithExplicitBlock
151
+ nested_schema = ParameterBuilder.new(parent_type: type).build(&block)
154
152
 
155
153
  case type
156
154
  when "object"
@@ -1,9 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "securerandom"
4
- require "json"
5
4
  require "timeout"
6
- require "uri"
7
5
 
8
6
  module Langchain::Vectorsearch
9
7
  class Epsilla < Base
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Langchain
4
- VERSION = "0.15.4"
4
+ VERSION = "0.15.5"
5
5
  end
data/lib/langchain.rb CHANGED
@@ -4,6 +4,9 @@ require "logger"
4
4
  require "pathname"
5
5
  require "rainbow"
6
6
  require "zeitwerk"
7
+ require "uri"
8
+ require "json"
9
+
7
10
  loader = Zeitwerk::Loader.for_gem
8
11
  loader.ignore("#{__dir__}/langchainrb.rb")
9
12
  loader.inflector.inflect(
@@ -30,6 +33,7 @@ loader.collapse("#{__dir__}/langchain/assistants")
30
33
 
31
34
  loader.collapse("#{__dir__}/langchain/tool/calculator")
32
35
  loader.collapse("#{__dir__}/langchain/tool/database")
36
+ loader.collapse("#{__dir__}/langchain/tool/docs_tool")
33
37
  loader.collapse("#{__dir__}/langchain/tool/file_system")
34
38
  loader.collapse("#{__dir__}/langchain/tool/google_search")
35
39
  loader.collapse("#{__dir__}/langchain/tool/ruby_code_interpreter")
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.15.4
4
+ version: 0.15.5
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-08-30 00:00:00.000000000 Z
11
+ date: 2024-09-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: baran