ruby_llm-red_candle 0.1.0 → 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/lib/ruby_llm/red_candle/capabilities.rb +1 -1
- data/lib/ruby_llm/red_candle/chat.rb +64 -18
- data/lib/ruby_llm/red_candle/models.rb +160 -18
- data/lib/ruby_llm/red_candle/tools.rb +59 -0
- data/lib/ruby_llm/red_candle/version.rb +1 -1
- data/lib/ruby_llm-red_candle.rb +1 -0
- data/ruby_llm-red_candle.gemspec +48 -0
- metadata +9 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3d28e7533552659e4618c7774c7758741d49433dfd320b0a483a0e93dfd20889
|
|
4
|
+
data.tar.gz: 7da03bf5b36d20608917f261b2ec284a6e4dd50bba9a95ebbbfa618f149a2948
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c05f230c8f8cc3d42b0ce4194f1d67d3964424a421b29745d3d8ebfeba1499b0e4a7452d8349a6940ba62139b745181e0b63f99a2a43cd68fce2ff4241bdbaf8
|
|
7
|
+
data.tar.gz: 0ed7589883dcd93fe699fc2f702563dbac6905a72309c13d7fb98042ec4189e3dac1827e6e016411856378544e6c4cbe5f8f0b14087541732e86c7da0c01a2c6
|
|
@@ -5,8 +5,10 @@ module RubyLLM
|
|
|
5
5
|
# Chat implementation for Red Candle provider
|
|
6
6
|
module Chat
|
|
7
7
|
# Override the base complete method to handle local execution
|
|
8
|
-
def complete(messages, tools:, temperature:, model:, params: {}, headers: {}, schema: nil, &block)
|
|
8
|
+
def complete(messages, tools:, temperature:, model:, params: {}, headers: {}, schema: nil, tool_prefs: nil, thinking: nil, &block)
|
|
9
9
|
_ = headers # Interface compatibility
|
|
10
|
+
_ = tool_prefs # Interface compatibility (not yet used by local models)
|
|
11
|
+
_ = thinking # Interface compatibility (not yet used by local models)
|
|
10
12
|
payload = RubyLLM::Utils.deep_merge(
|
|
11
13
|
render_payload(
|
|
12
14
|
messages,
|
|
@@ -23,11 +25,13 @@ module RubyLLM
|
|
|
23
25
|
perform_streaming_completion!(payload, &block)
|
|
24
26
|
else
|
|
25
27
|
result = perform_completion!(payload)
|
|
26
|
-
|
|
27
|
-
#
|
|
28
|
+
|
|
29
|
+
# perform_tool_completion! returns a Message directly
|
|
30
|
+
return result if result.is_a?(RubyLLM::Message)
|
|
31
|
+
|
|
32
|
+
# Convert hash result to Message object
|
|
28
33
|
content = result[:content]
|
|
29
|
-
|
|
30
|
-
estimated_output_tokens = (content.length / 4.0).round
|
|
34
|
+
estimated_output_tokens = (content.to_s.length / 4.0).round
|
|
31
35
|
estimated_input_tokens = estimate_input_tokens(payload[:messages])
|
|
32
36
|
|
|
33
37
|
RubyLLM::Message.new(
|
|
@@ -40,25 +44,31 @@ module RubyLLM
|
|
|
40
44
|
end
|
|
41
45
|
end
|
|
42
46
|
|
|
43
|
-
def render_payload(messages, tools:, temperature:, model:, stream:, schema:)
|
|
44
|
-
|
|
45
|
-
if tools && !tools.empty?
|
|
46
|
-
raise RubyLLM::Error.new(nil, "Red Candle provider does not support tool calling")
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
{
|
|
47
|
+
def render_payload(messages, tools:, temperature:, model:, stream:, schema:, tool_prefs: nil, thinking: nil)
|
|
48
|
+
payload = {
|
|
50
49
|
messages: messages,
|
|
51
50
|
temperature: temperature,
|
|
52
51
|
model: model.id,
|
|
53
52
|
stream: stream,
|
|
54
53
|
schema: schema
|
|
55
54
|
}
|
|
55
|
+
|
|
56
|
+
if tools && !tools.empty?
|
|
57
|
+
payload[:tools] = tools
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
payload
|
|
56
61
|
end
|
|
57
62
|
|
|
58
63
|
def perform_completion!(payload)
|
|
59
64
|
model = ensure_model_loaded!(payload[:model])
|
|
60
65
|
messages = format_messages(payload[:messages])
|
|
61
66
|
|
|
67
|
+
# Handle tool calling
|
|
68
|
+
if payload[:tools] && !payload[:tools].empty?
|
|
69
|
+
return perform_tool_completion!(model, messages, payload)
|
|
70
|
+
end
|
|
71
|
+
|
|
62
72
|
# Handle structured generation differently - we need to build the prompt
|
|
63
73
|
# with JSON instructions BEFORE applying the chat template
|
|
64
74
|
response = if payload[:schema]
|
|
@@ -110,6 +120,34 @@ module RubyLLM
|
|
|
110
120
|
|
|
111
121
|
private
|
|
112
122
|
|
|
123
|
+
def perform_tool_completion!(model, messages, payload)
|
|
124
|
+
# Convert RubyLLM tools to Candle tools
|
|
125
|
+
candle_tools = payload[:tools].values.map { |t| Tools.candle_tool_for(t) }
|
|
126
|
+
|
|
127
|
+
# Build generation config with enough room for thinking + tool calls
|
|
128
|
+
# Tool calling needs more tokens than regular chat (model uses <think> blocks)
|
|
129
|
+
payload[:max_tokens] ||= 1000
|
|
130
|
+
config = build_generation_config(payload)
|
|
131
|
+
|
|
132
|
+
# Use red-candle's chat_with_tools (execute: false — RubyLLM manages execution)
|
|
133
|
+
result = model.chat_with_tools(messages, tools: candle_tools, config: config)
|
|
134
|
+
|
|
135
|
+
content = result.text_response || ""
|
|
136
|
+
tool_calls = Tools.parse_tool_calls(result.tool_calls)
|
|
137
|
+
|
|
138
|
+
estimated_output_tokens = ((result.raw_response || "").length / 4.0).round
|
|
139
|
+
estimated_input_tokens = estimate_input_tokens(payload[:messages])
|
|
140
|
+
|
|
141
|
+
RubyLLM::Message.new(
|
|
142
|
+
role: :assistant,
|
|
143
|
+
content: content.empty? ? nil : content,
|
|
144
|
+
tool_calls: tool_calls,
|
|
145
|
+
model_id: payload[:model],
|
|
146
|
+
input_tokens: estimated_input_tokens,
|
|
147
|
+
output_tokens: estimated_output_tokens
|
|
148
|
+
)
|
|
149
|
+
end
|
|
150
|
+
|
|
113
151
|
# Build the prompt string from messages using the model's chat template
|
|
114
152
|
def build_prompt(model, messages)
|
|
115
153
|
if model.respond_to?(:apply_chat_template)
|
|
@@ -229,12 +267,17 @@ module RubyLLM
|
|
|
229
267
|
|
|
230
268
|
def format_messages(messages)
|
|
231
269
|
messages.map do |msg|
|
|
232
|
-
# Handle both hash and Message objects
|
|
233
270
|
if msg.is_a?(RubyLLM::Message)
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
271
|
+
if msg.tool_call?
|
|
272
|
+
Tools.format_tool_call(msg)
|
|
273
|
+
elsif msg.tool_result?
|
|
274
|
+
Tools.format_tool_result(msg)
|
|
275
|
+
else
|
|
276
|
+
{
|
|
277
|
+
role: msg.role.to_s,
|
|
278
|
+
content: extract_message_content_from_object(msg)
|
|
279
|
+
}
|
|
280
|
+
end
|
|
238
281
|
else
|
|
239
282
|
{
|
|
240
283
|
role: msg[:role].to_s,
|
|
@@ -292,8 +335,11 @@ module RubyLLM
|
|
|
292
335
|
# Use Red Candle's native structured generation which uses the Rust outlines crate
|
|
293
336
|
# for grammar-constrained generation. This ensures valid JSON output.
|
|
294
337
|
|
|
338
|
+
# Unwrap RubyLLM's schema wrapper format: {name: "response", schema: {...}, strict: true}
|
|
339
|
+
actual_schema = schema.is_a?(Hash) && (schema[:schema] || schema["schema"]) ? (schema[:schema] || schema["schema"]) : schema
|
|
340
|
+
|
|
295
341
|
# Normalize schema to ensure consistent symbol keys
|
|
296
|
-
normalized_schema = deep_symbolize_keys(
|
|
342
|
+
normalized_schema = deep_symbolize_keys(actual_schema)
|
|
297
343
|
|
|
298
344
|
# Validate schema before attempting generation
|
|
299
345
|
SchemaValidator.validate!(normalized_schema)
|
|
@@ -6,14 +6,33 @@ module RubyLLM
|
|
|
6
6
|
module Models
|
|
7
7
|
# TODO: red-candle supports more models, but let's start with some well tested ones.
|
|
8
8
|
SUPPORTED_MODELS = [
|
|
9
|
+
# Mistral
|
|
9
10
|
{
|
|
10
|
-
id: "
|
|
11
|
-
name: "
|
|
12
|
-
gguf_file: "
|
|
13
|
-
tokenizer: "
|
|
14
|
-
context_window:
|
|
15
|
-
family: "
|
|
16
|
-
|
|
11
|
+
id: "TheBloke/Mistral-7B-Instruct-v0.2-GGUF",
|
|
12
|
+
name: "Mistral 7B Instruct v0.2 (Quantized)",
|
|
13
|
+
gguf_file: "mistral-7b-instruct-v0.2.Q4_K_M.gguf",
|
|
14
|
+
tokenizer: "mistralai/Mistral-7B-Instruct-v0.2",
|
|
15
|
+
context_window: 32_768,
|
|
16
|
+
family: "mistral",
|
|
17
|
+
supports_chat: true,
|
|
18
|
+
supports_structured: true
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
id: "MaziyarPanahi/Mistral-7B-Instruct-v0.3-GGUF",
|
|
22
|
+
name: "Mistral 7B Instruct v0.3 (Quantized)",
|
|
23
|
+
gguf_file: "Mistral-7B-Instruct-v0.3.Q4_K_M.gguf",
|
|
24
|
+
tokenizer: "mistralai/Mistral-7B-Instruct-v0.3",
|
|
25
|
+
context_window: 32_768,
|
|
26
|
+
family: "mistral",
|
|
27
|
+
supports_chat: true,
|
|
28
|
+
supports_structured: true
|
|
29
|
+
},
|
|
30
|
+
# Llama / TinyLlama
|
|
31
|
+
{
|
|
32
|
+
id: "TinyLlama/TinyLlama-1.1B-Chat-v1.0",
|
|
33
|
+
name: "TinyLlama 1.1B Chat",
|
|
34
|
+
context_window: 2048,
|
|
35
|
+
family: "llama",
|
|
17
36
|
supports_chat: true,
|
|
18
37
|
supports_structured: true
|
|
19
38
|
},
|
|
@@ -23,28 +42,95 @@ module RubyLLM
|
|
|
23
42
|
gguf_file: "tinyllama-1.1b-chat-v1.0.Q4_K_M.gguf",
|
|
24
43
|
context_window: 2048,
|
|
25
44
|
family: "llama",
|
|
26
|
-
architecture: "llama",
|
|
27
45
|
supports_chat: true,
|
|
28
46
|
supports_structured: true
|
|
29
47
|
},
|
|
48
|
+
# Gemma
|
|
30
49
|
{
|
|
31
|
-
id: "
|
|
32
|
-
name: "
|
|
33
|
-
gguf_file: "
|
|
34
|
-
tokenizer: "
|
|
35
|
-
context_window:
|
|
36
|
-
family: "
|
|
37
|
-
architecture: "mistral",
|
|
50
|
+
id: "google/gemma-3-4b-it-qat-q4_0-gguf",
|
|
51
|
+
name: "Gemma 3 4B Instruct (Quantized)",
|
|
52
|
+
gguf_file: "gemma-3-4b-it-q4_0.gguf",
|
|
53
|
+
tokenizer: "google/gemma-3-4b-it",
|
|
54
|
+
context_window: 8192,
|
|
55
|
+
family: "gemma",
|
|
38
56
|
supports_chat: true,
|
|
39
57
|
supports_structured: true
|
|
40
58
|
},
|
|
59
|
+
# Qwen 2.5
|
|
41
60
|
{
|
|
42
61
|
id: "Qwen/Qwen2.5-1.5B-Instruct-GGUF",
|
|
43
62
|
name: "Qwen 2.5 1.5B Instruct (Quantized)",
|
|
44
63
|
gguf_file: "qwen2.5-1.5b-instruct-q4_k_m.gguf",
|
|
45
64
|
context_window: 32_768,
|
|
46
65
|
family: "qwen2",
|
|
47
|
-
|
|
66
|
+
supports_chat: true,
|
|
67
|
+
supports_structured: true
|
|
68
|
+
},
|
|
69
|
+
# Qwen 3
|
|
70
|
+
{
|
|
71
|
+
id: "Qwen/Qwen3-0.6B",
|
|
72
|
+
name: "Qwen3 0.6B",
|
|
73
|
+
context_window: 40_960,
|
|
74
|
+
family: "qwen3",
|
|
75
|
+
supports_chat: true,
|
|
76
|
+
supports_structured: true,
|
|
77
|
+
supports_tools: true
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
id: "MaziyarPanahi/Qwen3-0.6B-GGUF",
|
|
81
|
+
name: "Qwen3 0.6B (Quantized)",
|
|
82
|
+
gguf_file: "Qwen3-0.6B.Q4_K_M.gguf",
|
|
83
|
+
tokenizer: "Qwen/Qwen3-0.6B",
|
|
84
|
+
context_window: 40_960,
|
|
85
|
+
family: "qwen3",
|
|
86
|
+
supports_chat: true,
|
|
87
|
+
supports_structured: true,
|
|
88
|
+
supports_tools: true
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
id: "MaziyarPanahi/Qwen3-4B-GGUF",
|
|
92
|
+
name: "Qwen3 4B (Quantized)",
|
|
93
|
+
gguf_file: "Qwen3-4B.Q4_K_M.gguf",
|
|
94
|
+
tokenizer: "Qwen/Qwen3-4B",
|
|
95
|
+
context_window: 40_960,
|
|
96
|
+
family: "qwen3",
|
|
97
|
+
supports_chat: true,
|
|
98
|
+
supports_structured: true,
|
|
99
|
+
supports_tools: true
|
|
100
|
+
},
|
|
101
|
+
# SmolLM2
|
|
102
|
+
{
|
|
103
|
+
id: "HuggingFaceTB/SmolLM2-360M-Instruct",
|
|
104
|
+
name: "SmolLM2 360M Instruct",
|
|
105
|
+
context_window: 8192,
|
|
106
|
+
family: "llama",
|
|
107
|
+
supports_chat: true,
|
|
108
|
+
supports_structured: true
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
id: "HuggingFaceTB/SmolLM2-360M-Instruct-GGUF",
|
|
112
|
+
name: "SmolLM2 360M Instruct (Quantized)",
|
|
113
|
+
gguf_file: "smollm2-360m-instruct-q8_0.gguf",
|
|
114
|
+
context_window: 8192,
|
|
115
|
+
family: "llama",
|
|
116
|
+
supports_chat: true,
|
|
117
|
+
supports_structured: true
|
|
118
|
+
},
|
|
119
|
+
# Phi
|
|
120
|
+
{
|
|
121
|
+
id: "microsoft/phi-2",
|
|
122
|
+
name: "Phi 2",
|
|
123
|
+
context_window: 2048,
|
|
124
|
+
family: "phi",
|
|
125
|
+
supports_chat: true,
|
|
126
|
+
supports_structured: true
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
id: "TheBloke/phi-2-GGUF",
|
|
130
|
+
name: "Phi 2 (Quantized)",
|
|
131
|
+
gguf_file: "phi-2.Q4_K_M.gguf",
|
|
132
|
+
context_window: 2048,
|
|
133
|
+
family: "phi",
|
|
48
134
|
supports_chat: true,
|
|
49
135
|
supports_structured: true
|
|
50
136
|
},
|
|
@@ -53,10 +139,66 @@ module RubyLLM
|
|
|
53
139
|
name: "Phi 3 Mini 4K Instruct",
|
|
54
140
|
context_window: 4096,
|
|
55
141
|
family: "phi",
|
|
56
|
-
architecture: "phi",
|
|
57
142
|
supports_chat: true,
|
|
58
143
|
supports_structured: true
|
|
59
|
-
}
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
id: "microsoft/Phi-3-mini-4k-instruct-gguf",
|
|
147
|
+
name: "Phi 3 Mini 4K Instruct (Quantized)",
|
|
148
|
+
gguf_file: "Phi-3-mini-4k-instruct-q4.gguf",
|
|
149
|
+
context_window: 4096,
|
|
150
|
+
family: "phi",
|
|
151
|
+
supports_chat: true,
|
|
152
|
+
supports_structured: true
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
id: "microsoft/phi-4-gguf",
|
|
156
|
+
name: "Phi 4 (Quantized)",
|
|
157
|
+
gguf_file: "phi-4-Q4_K_S.gguf",
|
|
158
|
+
context_window: 16_384,
|
|
159
|
+
family: "phi",
|
|
160
|
+
supports_chat: true,
|
|
161
|
+
supports_structured: true
|
|
162
|
+
},
|
|
163
|
+
# Yi
|
|
164
|
+
{
|
|
165
|
+
id: "bartowski/Yi-1.5-6B-Chat-GGUF",
|
|
166
|
+
name: "Yi 1.5 6B Chat (Quantized)",
|
|
167
|
+
gguf_file: "Yi-1.5-6B-Chat-Q4_K_M.gguf",
|
|
168
|
+
tokenizer: "01-ai/Yi-1.5-6B-Chat",
|
|
169
|
+
context_window: 4096,
|
|
170
|
+
family: "llama",
|
|
171
|
+
supports_chat: true,
|
|
172
|
+
supports_structured: true
|
|
173
|
+
},
|
|
174
|
+
# Granite
|
|
175
|
+
{
|
|
176
|
+
id: "ibm-granite/granite-7b-instruct",
|
|
177
|
+
name: "Granite 7B Instruct",
|
|
178
|
+
context_window: 4096,
|
|
179
|
+
family: "granite",
|
|
180
|
+
supports_chat: true,
|
|
181
|
+
supports_structured: true
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
id: "ibm-granite/granite-4.0-micro",
|
|
185
|
+
name: "Granite 4.0 Micro",
|
|
186
|
+
context_window: 8192,
|
|
187
|
+
family: "granite",
|
|
188
|
+
supports_chat: true,
|
|
189
|
+
supports_structured: true
|
|
190
|
+
},
|
|
191
|
+
# GLM-4
|
|
192
|
+
{
|
|
193
|
+
id: "bartowski/THUDM_GLM-4-9B-0414-GGUF",
|
|
194
|
+
name: "GLM-4 9B (Quantized)",
|
|
195
|
+
gguf_file: "THUDM_GLM-4-9B-0414-Q4_K_M.gguf",
|
|
196
|
+
tokenizer: "THUDM/GLM-4-9B-0414",
|
|
197
|
+
context_window: 131_072,
|
|
198
|
+
family: "glm4",
|
|
199
|
+
supports_chat: true,
|
|
200
|
+
supports_structured: true
|
|
201
|
+
},
|
|
60
202
|
].freeze
|
|
61
203
|
|
|
62
204
|
def list_models
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "securerandom"
|
|
4
|
+
|
|
5
|
+
module RubyLLM
|
|
6
|
+
module RedCandle
|
|
7
|
+
# Tool calling support for Red Candle provider.
|
|
8
|
+
# Bridges between RubyLLM::Tool and Candle::Tool formats.
|
|
9
|
+
module Tools
|
|
10
|
+
module_function
|
|
11
|
+
|
|
12
|
+
# Convert a RubyLLM::Tool to a Candle::Tool (without a callable block —
|
|
13
|
+
# RubyLLM manages tool execution itself)
|
|
14
|
+
def candle_tool_for(tool)
|
|
15
|
+
parameters = tool.params_schema ||
|
|
16
|
+
RubyLLM::Tool::SchemaDefinition.from_parameters(tool.parameters)&.json_schema ||
|
|
17
|
+
{ type: "object", properties: {}, required: [] }
|
|
18
|
+
|
|
19
|
+
::Candle::Tool.new(
|
|
20
|
+
name: tool.name,
|
|
21
|
+
description: tool.description || "",
|
|
22
|
+
parameters: parameters
|
|
23
|
+
) { |_args| nil } # No-op block — RubyLLM handles execution
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Convert Candle::ToolCall objects to RubyLLM tool_calls hash format
|
|
27
|
+
# RubyLLM expects: { "call_id" => RubyLLM::ToolCall, ... }
|
|
28
|
+
def parse_tool_calls(candle_tool_calls)
|
|
29
|
+
return nil if candle_tool_calls.nil? || candle_tool_calls.empty?
|
|
30
|
+
|
|
31
|
+
tool_calls = {}
|
|
32
|
+
candle_tool_calls.each do |tc|
|
|
33
|
+
call_id = "call_#{SecureRandom.hex(12)}"
|
|
34
|
+
tool_calls[call_id] = RubyLLM::ToolCall.new(
|
|
35
|
+
id: call_id,
|
|
36
|
+
name: tc.name,
|
|
37
|
+
arguments: tc.arguments
|
|
38
|
+
)
|
|
39
|
+
end
|
|
40
|
+
tool_calls
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Format a tool call message (assistant message with tool_calls) for
|
|
44
|
+
# sending back to the model. Injects tool calls into the content.
|
|
45
|
+
def format_tool_call(msg)
|
|
46
|
+
content = msg.content.to_s
|
|
47
|
+
msg.tool_calls&.each_value do |tc|
|
|
48
|
+
content += "\n<tool_call>\n#{JSON.generate({ name: tc.name, arguments: tc.arguments })}\n</tool_call>"
|
|
49
|
+
end
|
|
50
|
+
{ role: "assistant", content: content }
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Format a tool result message for sending back to the model
|
|
54
|
+
def format_tool_result(msg)
|
|
55
|
+
{ role: "tool", content: msg.content.to_s }
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
data/lib/ruby_llm-red_candle.rb
CHANGED
|
@@ -8,6 +8,7 @@ require_relative "ruby_llm/red_candle/schema_validator"
|
|
|
8
8
|
require_relative "ruby_llm/red_candle/capabilities"
|
|
9
9
|
require_relative "ruby_llm/red_candle/models"
|
|
10
10
|
require_relative "ruby_llm/red_candle/streaming"
|
|
11
|
+
require_relative "ruby_llm/red_candle/tools"
|
|
11
12
|
require_relative "ruby_llm/red_candle/chat"
|
|
12
13
|
require_relative "ruby_llm/red_candle/provider"
|
|
13
14
|
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "lib/ruby_llm/red_candle/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = "ruby_llm-red_candle"
|
|
7
|
+
spec.version = RubyLLM::RedCandle::VERSION
|
|
8
|
+
spec.authors = ["Chris Petersen"]
|
|
9
|
+
spec.email = ["chris@scientist.com"]
|
|
10
|
+
|
|
11
|
+
spec.summary = "Red Candle provider for RubyLLM - local LLM execution using quantized GGUF models"
|
|
12
|
+
spec.description = <<~DESC
|
|
13
|
+
A RubyLLM plugin that enables local LLM execution using the Red Candle gem.
|
|
14
|
+
Run quantized GGUF models directly in Ruby without external API calls.
|
|
15
|
+
Supports streaming, structured output, and multiple model architectures
|
|
16
|
+
including Gemma, Llama, Qwen, Mistral, and Phi.
|
|
17
|
+
DESC
|
|
18
|
+
spec.homepage = "https://github.com/scientist-labs/ruby_llm-red_candle"
|
|
19
|
+
spec.license = "MIT"
|
|
20
|
+
spec.required_ruby_version = ">= 3.1.0"
|
|
21
|
+
|
|
22
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
|
23
|
+
spec.metadata["source_code_uri"] = spec.homepage
|
|
24
|
+
spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"
|
|
25
|
+
spec.metadata["rubygems_mfa_required"] = "true"
|
|
26
|
+
|
|
27
|
+
# Specify which files should be added to the gem when it is released.
|
|
28
|
+
spec.files = Dir.chdir(__dir__) do
|
|
29
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
|
30
|
+
(File.expand_path(f) == __FILE__) ||
|
|
31
|
+
f.start_with?(*%w[bin/ test/ spec/ features/ .git .github appveyor Gemfile])
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
spec.bindir = "exe"
|
|
35
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
|
36
|
+
spec.require_paths = ["lib"]
|
|
37
|
+
|
|
38
|
+
# Runtime dependencies
|
|
39
|
+
spec.add_dependency "ruby_llm", ">= 1.10", "< 3.0"
|
|
40
|
+
spec.add_dependency "red-candle", "~> 1.5"
|
|
41
|
+
|
|
42
|
+
# Development dependencies
|
|
43
|
+
spec.add_development_dependency "rake", "~> 13.0"
|
|
44
|
+
spec.add_development_dependency "rspec", "~> 3.12"
|
|
45
|
+
spec.add_development_dependency "rubocop", "~> 1.0"
|
|
46
|
+
spec.add_development_dependency "rubocop-rspec", "~> 3.0"
|
|
47
|
+
spec.add_development_dependency "simplecov", "~> 0.22"
|
|
48
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ruby_llm-red_candle
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Chris Petersen
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-03-27 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: ruby_llm
|
|
@@ -16,7 +16,7 @@ dependencies:
|
|
|
16
16
|
requirements:
|
|
17
17
|
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '1.
|
|
19
|
+
version: '1.10'
|
|
20
20
|
- - "<"
|
|
21
21
|
- !ruby/object:Gem::Version
|
|
22
22
|
version: '3.0'
|
|
@@ -26,7 +26,7 @@ dependencies:
|
|
|
26
26
|
requirements:
|
|
27
27
|
- - ">="
|
|
28
28
|
- !ruby/object:Gem::Version
|
|
29
|
-
version: '1.
|
|
29
|
+
version: '1.10'
|
|
30
30
|
- - "<"
|
|
31
31
|
- !ruby/object:Gem::Version
|
|
32
32
|
version: '3.0'
|
|
@@ -36,14 +36,14 @@ dependencies:
|
|
|
36
36
|
requirements:
|
|
37
37
|
- - "~>"
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
|
-
version: '1.
|
|
39
|
+
version: '1.5'
|
|
40
40
|
type: :runtime
|
|
41
41
|
prerelease: false
|
|
42
42
|
version_requirements: !ruby/object:Gem::Requirement
|
|
43
43
|
requirements:
|
|
44
44
|
- - "~>"
|
|
45
45
|
- !ruby/object:Gem::Version
|
|
46
|
-
version: '1.
|
|
46
|
+
version: '1.5'
|
|
47
47
|
- !ruby/object:Gem::Dependency
|
|
48
48
|
name: rake
|
|
49
49
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -140,7 +140,9 @@ files:
|
|
|
140
140
|
- lib/ruby_llm/red_candle/provider.rb
|
|
141
141
|
- lib/ruby_llm/red_candle/schema_validator.rb
|
|
142
142
|
- lib/ruby_llm/red_candle/streaming.rb
|
|
143
|
+
- lib/ruby_llm/red_candle/tools.rb
|
|
143
144
|
- lib/ruby_llm/red_candle/version.rb
|
|
145
|
+
- ruby_llm-red_candle.gemspec
|
|
144
146
|
homepage: https://github.com/scientist-labs/ruby_llm-red_candle
|
|
145
147
|
licenses:
|
|
146
148
|
- MIT
|
|
@@ -164,7 +166,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
164
166
|
- !ruby/object:Gem::Version
|
|
165
167
|
version: '0'
|
|
166
168
|
requirements: []
|
|
167
|
-
rubygems_version: 3.5.
|
|
169
|
+
rubygems_version: 3.5.22
|
|
168
170
|
signing_key:
|
|
169
171
|
specification_version: 4
|
|
170
172
|
summary: Red Candle provider for RubyLLM - local LLM execution using quantized GGUF
|