ruby_llm-red_candle 0.1.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.
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyLLM
4
+ module RedCandle
5
+ # Validates JSON schemas for structured generation
6
+ module SchemaValidator
7
+ class << self
8
+ # Validate a schema for structured generation
9
+ # @param schema [Hash] the JSON schema to validate
10
+ # @raise [RubyLLM::Error] if the schema is invalid
11
+ # @return [true] if validation passes
12
+ def validate!(schema)
13
+ errors = validate(schema)
14
+ return true if errors.empty?
15
+
16
+ raise RubyLLM::Error.new(
17
+ nil,
18
+ build_error_message(errors, schema)
19
+ )
20
+ end
21
+
22
+ # Validate a schema and return any errors
23
+ # @param schema [Hash] the JSON schema to validate
24
+ # @return [Array<String>] list of validation errors (empty if valid)
25
+ def validate(schema)
26
+ errors = []
27
+
28
+ # Check schema is a Hash
29
+ unless schema.is_a?(Hash)
30
+ errors << "Schema must be a Hash, got #{schema.class.name}"
31
+ return errors # Can't continue validation
32
+ end
33
+
34
+ # Check type is "object"
35
+ schema_type = schema[:type] || schema["type"]
36
+ if schema_type.nil?
37
+ errors << "Schema must have a 'type' field"
38
+ elsif schema_type.to_s != "object"
39
+ errors << "Schema type must be 'object' for structured generation, got '#{schema_type}'"
40
+ end
41
+
42
+ # Check properties exist and are valid
43
+ properties = schema[:properties] || schema["properties"]
44
+ if properties.nil?
45
+ errors << "Schema must have a 'properties' field defining the expected output structure"
46
+ elsif !properties.is_a?(Hash)
47
+ errors << "Schema 'properties' must be a Hash, got #{properties.class.name}"
48
+ elsif properties.empty?
49
+ errors << "Schema 'properties' must define at least one property"
50
+ else
51
+ # Validate each property has a type
52
+ properties.each do |key, value|
53
+ unless value.is_a?(Hash)
54
+ errors << "Property '#{key}' must be a Hash with at least a 'type' field"
55
+ next
56
+ end
57
+
58
+ prop_type = value[:type] || value["type"]
59
+ if prop_type.nil?
60
+ errors << "Property '#{key}' must have a 'type' field"
61
+ end
62
+ end
63
+ end
64
+
65
+ errors
66
+ end
67
+
68
+ # Check if a schema is valid without raising
69
+ # @param schema [Hash] the JSON schema to validate
70
+ # @return [Boolean] true if valid
71
+ def valid?(schema)
72
+ validate(schema).empty?
73
+ end
74
+
75
+ private
76
+
77
+ def build_error_message(errors, schema)
78
+ message = ["Invalid schema for structured generation:"]
79
+ errors.each { |e| message << " - #{e}" }
80
+ message << ""
81
+ message << "Expected a JSON Schema like:"
82
+ message << " {"
83
+ message << " type: 'object',"
84
+ message << " properties: {"
85
+ message << " name: { type: 'string' },"
86
+ message << " age: { type: 'integer' }"
87
+ message << " },"
88
+ message << " required: ['name', 'age']"
89
+ message << " }"
90
+ message << ""
91
+ message << "Received: #{truncate_schema(schema)}"
92
+ message.join("\n")
93
+ end
94
+
95
+ def truncate_schema(schema)
96
+ str = schema.inspect
97
+ str.length > 200 ? "#{str[0..200]}..." : str
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyLLM
4
+ module RedCandle
5
+ # Streaming methods of the RedCandle integration
6
+ module Streaming
7
+ def stream(payload, &block)
8
+ if payload[:stream]
9
+ perform_streaming_completion!(payload, &block)
10
+ else
11
+ # Non-streaming fallback
12
+ result = perform_completion!(payload)
13
+ # Yield the complete result as a single chunk
14
+ chunk = {
15
+ content: result[:content],
16
+ role: result[:role],
17
+ finish_reason: result[:finish_reason]
18
+ }
19
+ block.call(chunk)
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def stream_processor
26
+ # Red Candle handles streaming internally through blocks
27
+ # This method is here for compatibility with the base streaming interface
28
+ nil
29
+ end
30
+
31
+ def process_stream_response(response)
32
+ # Red Candle doesn't use HTTP responses
33
+ # Streaming is handled directly in perform_streaming_completion!
34
+ response
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyLLM
4
+ module RedCandle
5
+ VERSION = "0.1.0"
6
+ end
7
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ruby_llm"
4
+
5
+ require_relative "ruby_llm/red_candle/version"
6
+ require_relative "ruby_llm/red_candle/configuration"
7
+ require_relative "ruby_llm/red_candle/schema_validator"
8
+ require_relative "ruby_llm/red_candle/capabilities"
9
+ require_relative "ruby_llm/red_candle/models"
10
+ require_relative "ruby_llm/red_candle/streaming"
11
+ require_relative "ruby_llm/red_candle/chat"
12
+ require_relative "ruby_llm/red_candle/provider"
13
+
14
+ module RubyLLM
15
+ # Red Candle plugin module - provides local LLM execution using quantized GGUF models
16
+ module RedCandle
17
+ class << self
18
+ # Register the provider with RubyLLM
19
+ def register!
20
+ RubyLLM::Provider.register :red_candle, Provider
21
+
22
+ # Register Red Candle models with the global registry
23
+ Provider.models.each do |model|
24
+ RubyLLM.models.instance_variable_get(:@models) << model
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ # Auto-register when the gem is loaded
32
+ RubyLLM::RedCandle.register!
metadata ADDED
@@ -0,0 +1,172 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby_llm-red_candle
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Chris Petersen
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2025-12-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ruby_llm
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '1.2'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '3.0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '1.2'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '3.0'
33
+ - !ruby/object:Gem::Dependency
34
+ name: red-candle
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.3'
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '1.3'
47
+ - !ruby/object:Gem::Dependency
48
+ name: rake
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '13.0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '13.0'
61
+ - !ruby/object:Gem::Dependency
62
+ name: rspec
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '3.12'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '3.12'
75
+ - !ruby/object:Gem::Dependency
76
+ name: rubocop
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '1.0'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '1.0'
89
+ - !ruby/object:Gem::Dependency
90
+ name: rubocop-rspec
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '3.0'
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '3.0'
103
+ - !ruby/object:Gem::Dependency
104
+ name: simplecov
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '0.22'
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - "~>"
115
+ - !ruby/object:Gem::Version
116
+ version: '0.22'
117
+ description: |
118
+ A RubyLLM plugin that enables local LLM execution using the Red Candle gem.
119
+ Run quantized GGUF models directly in Ruby without external API calls.
120
+ Supports streaming, structured output, and multiple model architectures
121
+ including Gemma, Llama, Qwen, Mistral, and Phi.
122
+ email:
123
+ - chris@scientist.com
124
+ executables: []
125
+ extensions: []
126
+ extra_rdoc_files: []
127
+ files:
128
+ - ".rspec"
129
+ - ".rubocop.yml"
130
+ - CHANGELOG.md
131
+ - LICENSE.txt
132
+ - README.md
133
+ - Rakefile
134
+ - examples/smoke_test.rb
135
+ - lib/ruby_llm-red_candle.rb
136
+ - lib/ruby_llm/red_candle/capabilities.rb
137
+ - lib/ruby_llm/red_candle/chat.rb
138
+ - lib/ruby_llm/red_candle/configuration.rb
139
+ - lib/ruby_llm/red_candle/models.rb
140
+ - lib/ruby_llm/red_candle/provider.rb
141
+ - lib/ruby_llm/red_candle/schema_validator.rb
142
+ - lib/ruby_llm/red_candle/streaming.rb
143
+ - lib/ruby_llm/red_candle/version.rb
144
+ homepage: https://github.com/scientist-labs/ruby_llm-red_candle
145
+ licenses:
146
+ - MIT
147
+ metadata:
148
+ homepage_uri: https://github.com/scientist-labs/ruby_llm-red_candle
149
+ source_code_uri: https://github.com/scientist-labs/ruby_llm-red_candle
150
+ changelog_uri: https://github.com/scientist-labs/ruby_llm-red_candle/blob/main/CHANGELOG.md
151
+ rubygems_mfa_required: 'true'
152
+ post_install_message:
153
+ rdoc_options: []
154
+ require_paths:
155
+ - lib
156
+ required_ruby_version: !ruby/object:Gem::Requirement
157
+ requirements:
158
+ - - ">="
159
+ - !ruby/object:Gem::Version
160
+ version: 3.1.0
161
+ required_rubygems_version: !ruby/object:Gem::Requirement
162
+ requirements:
163
+ - - ">="
164
+ - !ruby/object:Gem::Version
165
+ version: '0'
166
+ requirements: []
167
+ rubygems_version: 3.5.3
168
+ signing_key:
169
+ specification_version: 4
170
+ summary: Red Candle provider for RubyLLM - local LLM execution using quantized GGUF
171
+ models
172
+ test_files: []