girb-ruby_llm 0.1.2 → 0.2.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: cfe19c19205f70c38e3f95b1fca105e6c3c5d5c3398871e1a43cf5310e7bfb7a
4
- data.tar.gz: 52dcce3593879b4bd66864f8928e5b7eb0aa1f4adc186c62bc665bfc217c1fd5
3
+ metadata.gz: 53c8af5d1f30750451fed2b555cd064e492468da3e7954cf5976443374eb4d4d
4
+ data.tar.gz: '0149788d1aa79cd0de9bd0531ca8e855e4934c7e3b63a2fa59000ba2469e6048'
5
5
  SHA512:
6
- metadata.gz: e030b3dd7df74d07d15b6bfef72e61c7f5c1d9c6d8aa093eed9440855960c8e0773bb3046461a8d05e496e07d8891d6366a4e17bac299cb74d4d8da3bfb5fc2b
7
- data.tar.gz: eb256345ace0da90621bd10069a4b0ed3dc94bc72b768d5da79cfd3cf4f558250fae6d9aa0aa3782aa66c632c86783931cf025739dab8dd6e1826b6010dca17f
6
+ metadata.gz: 78f109efbd1bb1a677295a8de6bc319f5dbd979df13bac7222cdf8015468b3973b88322bf7ca1cfb528b91d35ed1c2b220ca689eaa04147621dd18ae5abe1c35
7
+ data.tar.gz: 7770dbb62a2f71cf5197bb0db15a4b526824cf6d4f5a1a410170672dce64cb92251efcefabc71d851f75ab1b8d719a98b974cbea9e5c8d3fbbd964bbc891ee37
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.2.0] - 2026-02-05
4
+
5
+ ### Added
6
+
7
+ - Debug gem (rdbg) support for AI-assisted debugging
8
+
3
9
  ## [0.1.2] - 2026-02-03
4
10
 
5
11
  ### Fixed
@@ -6,23 +6,11 @@ require "girb/providers/base"
6
6
  module Girb
7
7
  module Providers
8
8
  class RubyLlm < Base
9
- # Thread-local storage for current binding
10
- def self.current_binding=(binding)
11
- Thread.current[:girb_ruby_llm_binding] = binding
12
- end
13
-
14
- def self.current_binding
15
- Thread.current[:girb_ruby_llm_binding]
16
- end
17
-
18
9
  def initialize(model: nil)
19
10
  @model = model
20
11
  end
21
12
 
22
13
  def chat(messages:, system_prompt:, tools:, binding: nil)
23
- # Store binding for tool execution
24
- self.class.current_binding = binding
25
-
26
14
  # Use specified model or RubyLLM's default
27
15
  chat_options = @model ? { model: @model } : {}
28
16
  ruby_llm_chat = ::RubyLLM.chat(**chat_options)
@@ -30,31 +18,41 @@ module Girb
30
18
  # Set system prompt
31
19
  ruby_llm_chat.with_instructions(system_prompt) if system_prompt && !system_prompt.empty?
32
20
 
33
- # Add tools
21
+ # Add tool schemas (for API payload generation only, not auto-executed)
34
22
  tool_instances = build_tools(tools)
35
23
  tool_instances.each { |tool| ruby_llm_chat.with_tool(tool) }
36
24
 
37
- # Add messages except the last user message
38
- add_messages_to_chat(ruby_llm_chat, messages[0..-2])
25
+ # Add all messages to the chat
26
+ add_messages_to_chat(ruby_llm_chat, messages)
39
27
 
40
- # Get the last user message
41
- last_message = messages.last
42
- last_content = extract_content(last_message)
43
-
44
- # Send the request - RubyLLM will auto-execute tools
45
- response = ruby_llm_chat.ask(last_content)
28
+ # Get raw response without auto-executing tools
29
+ response = raw_complete(ruby_llm_chat)
46
30
 
47
31
  parse_response(response)
48
32
  rescue Faraday::BadRequestError => e
49
33
  Response.new(error: "API Error: #{e.message}")
50
34
  rescue StandardError => e
51
35
  Response.new(error: "Error: #{e.message}")
52
- ensure
53
- self.class.current_binding = nil
54
36
  end
55
37
 
56
38
  private
57
39
 
40
+ # Call provider.complete() directly, bypassing RubyLLM's handle_tool_calls.
41
+ # This returns the raw response so the caller can handle tool execution.
42
+ def raw_complete(chat)
43
+ provider = chat.instance_variable_get(:@provider)
44
+ provider.complete(
45
+ chat.messages,
46
+ tools: chat.tools,
47
+ temperature: chat.instance_variable_get(:@temperature),
48
+ model: chat.model,
49
+ params: chat.params,
50
+ headers: chat.headers,
51
+ schema: chat.schema,
52
+ thinking: chat.instance_variable_get(:@thinking)
53
+ )
54
+ end
55
+
58
56
  def add_messages_to_chat(chat, messages)
59
57
  messages.each do |msg|
60
58
  case msg[:role]
@@ -63,13 +61,13 @@ module Girb
63
61
  when :assistant
64
62
  chat.add_message(role: :assistant, content: msg[:content])
65
63
  when :tool_call
66
- # Add as assistant message with tool_calls
64
+ id = msg[:id] || "call_#{SecureRandom.hex(12)}"
67
65
  chat.add_message(
68
66
  role: :assistant,
69
67
  content: nil,
70
68
  tool_calls: {
71
- msg[:name] => ::RubyLLM::ToolCall.new(
72
- id: msg[:id] || "call_#{SecureRandom.hex(12)}",
69
+ id => ::RubyLLM::ToolCall.new(
70
+ id: id,
73
71
  name: msg[:name],
74
72
  arguments: msg[:args]
75
73
  )
@@ -85,15 +83,6 @@ module Girb
85
83
  end
86
84
  end
87
85
 
88
- def extract_content(message)
89
- case message[:role]
90
- when :user, :assistant
91
- message[:content]
92
- else
93
- message[:content].to_s
94
- end
95
- end
96
-
97
86
  def build_tools(tools)
98
87
  return [] if tools.nil? || tools.empty?
99
88
 
@@ -107,11 +96,10 @@ module Girb
107
96
  tool_description = tool_def[:description]
108
97
  tool_parameters = tool_def[:parameters] || {}
109
98
 
110
- # Create a dynamic tool class
99
+ # Create a dynamic tool class for schema generation only
111
100
  tool_class = Class.new(::RubyLLM::Tool) do
112
101
  description tool_description
113
102
 
114
- # Define parameters
115
103
  properties = tool_parameters[:properties] || {}
116
104
  required_params = tool_parameters[:required] || []
117
105
 
@@ -122,41 +110,11 @@ module Girb
122
110
  required: required_params.include?(prop_name.to_s) || required_params.include?(prop_name)
123
111
  end
124
112
 
125
- # Store tool_name for execute method and override name for RubyLLM
126
- define_method(:girb_tool_name) { tool_name }
127
113
  define_method(:name) { tool_name }
128
114
 
129
- # Execute method - actually execute the girb tool
130
- define_method(:execute) do |**args|
131
- tool_name_for_log = girb_tool_name
132
-
133
- if Girb.configuration&.debug
134
- args_str = args.map { |k, v| "#{k}: #{v.inspect}" }.join(", ")
135
- puts "[girb] Tool: #{tool_name_for_log}(#{args_str})"
136
- end
137
-
138
- binding = Girb::Providers::RubyLlm.current_binding
139
- girb_tool_class = Girb::Tools.find_tool(tool_name_for_log)
140
-
141
- unless girb_tool_class
142
- return { error: "Unknown tool: #{tool_name_for_log}" }
143
- end
144
-
145
- girb_tool = girb_tool_class.new
146
-
147
- result = if binding
148
- girb_tool.execute(binding, **args)
149
- else
150
- { error: "No binding available for tool execution" }
151
- end
152
-
153
- if Girb.configuration&.debug && result.is_a?(Hash) && result[:error]
154
- puts "[girb] Tool error: #{result[:error]}"
155
- end
156
-
157
- result
158
- rescue StandardError => e
159
- { error: "Tool execution failed: #{e.class} - #{e.message}" }
115
+ # Not used tool execution is handled by the caller's tool loop
116
+ define_method(:execute) do |**_args|
117
+ raise "Tool execution should be handled by the caller, not by the provider"
160
118
  end
161
119
  end
162
120
 
@@ -177,6 +135,7 @@ module Girb
177
135
 
178
136
  response.tool_calls.map do |_id, tool_call|
179
137
  {
138
+ id: tool_call.id,
180
139
  name: tool_call.name.to_s,
181
140
  args: tool_call.arguments || {}
182
141
  }
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GirbRubyLlm
4
- VERSION = "0.1.2"
4
+ VERSION = "0.2.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: girb-ruby_llm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - rira100000000