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 +4 -4
- data/CHANGELOG.md +6 -0
- data/lib/girb/providers/ruby_llm.rb +29 -70
- data/lib/girb-ruby_llm/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 53c8af5d1f30750451fed2b555cd064e492468da3e7954cf5976443374eb4d4d
|
|
4
|
+
data.tar.gz: '0149788d1aa79cd0de9bd0531ca8e855e4934c7e3b63a2fa59000ba2469e6048'
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 78f109efbd1bb1a677295a8de6bc319f5dbd979df13bac7222cdf8015468b3973b88322bf7ca1cfb528b91d35ed1c2b220ca689eaa04147621dd18ae5abe1c35
|
|
7
|
+
data.tar.gz: 7770dbb62a2f71cf5197bb0db15a4b526824cf6d4f5a1a410170672dce64cb92251efcefabc71d851f75ab1b8d719a98b974cbea9e5c8d3fbbd964bbc891ee37
|
data/CHANGELOG.md
CHANGED
|
@@ -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
|
|
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
|
|
38
|
-
add_messages_to_chat(ruby_llm_chat, messages
|
|
25
|
+
# Add all messages to the chat
|
|
26
|
+
add_messages_to_chat(ruby_llm_chat, messages)
|
|
39
27
|
|
|
40
|
-
# Get
|
|
41
|
-
|
|
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
|
-
|
|
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
|
-
|
|
72
|
-
id:
|
|
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
|
-
#
|
|
130
|
-
define_method(:execute) do |**
|
|
131
|
-
|
|
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
|
}
|