rubycanusellm 0.4.1 → 0.5.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: 4fa122c59f084a74df8fe6cc1b7b0cf26982d5d7dd29a1dbf37937f821024e08
4
- data.tar.gz: 3d01defe930449e9b6cd4adc974c6d051b3af6171287673e1cdd4b679b4648a0
3
+ metadata.gz: 8366062327382434c0f86c1cb30a0a2265b1d26e7e512b294884aeac93e09468
4
+ data.tar.gz: 510d3d9d0051a4cdcb63ecdf7e0d1f4e536e27701a64504cd57fb555868aba1d
5
5
  SHA512:
6
- metadata.gz: 968934bfc95e1d8b5b1e8400ef9a784aa391db310984849ab4a5208c80c8378792afc26463ff4efb5b7f08772fbe72cf71266a2383cd41f1bb2c44078e6da7a8
7
- data.tar.gz: 69800687f81c9753267db171bd9a64e74097126f16fa9ffaade1704536976fca53f0c151e4ab187ba2daf9febe45d5614ff9ff8a700c3265593b983db1595494
6
+ metadata.gz: 711b8791cc6a9aa49362aaeb1a1da4d03071ec0ab14709e2b3ab20ec418752ce48232cace46103337b58f3daab643efd03a4f08259f994c848bf8c41efb8f3a1
7
+ data.tar.gz: 6c3adfcaa2032802fdfbb8f861dea1d89e56d177be3fbf2f761c47457af573c7a7581cd5727ce736b31738f33649e1ea8b247c18bbc8bf1b7364824966aeaeb8
data/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.5.0] - 2026-04-03
4
+
5
+ ### Added
6
+
7
+ - `RubyCanUseLLM::Prompt` — lightweight prompt template system with ERB and YAML file support
8
+ - Inline prompts via `Prompt.new(system:, user:, assistant:)` + `render(**variables)`
9
+ - File-based prompts via `Prompt.load("path/to/prompt.yml", **variables)`
10
+ - Full ERB support: loops, conditionals, any Ruby expression
11
+ - Clear error messages for missing variables and invalid roles
12
+
3
13
  ## [0.4.1] - 2026-04-03
4
14
 
5
15
  ### Added
data/README.md CHANGED
@@ -197,12 +197,53 @@ rescue RubyCanUseLLM::ProviderError => e
197
197
  end
198
198
  ```
199
199
 
200
+ ### Prompt Templates
201
+
202
+ Keep prompts out of your Ruby code. Define them in YAML files with ERB for dynamic content:
203
+
204
+ ```yaml
205
+ # prompts/commodity_analysis.yml
206
+ system: |
207
+ You are an expert in <%= domain %> classification.
208
+ user: |
209
+ Analyze this item: <%= description %>
210
+ <% if references.any? %>
211
+ Similar references:
212
+ <% references.each do |ref| %>
213
+ - <%= ref %>
214
+ <% end %>
215
+ <% end %>
216
+ ```
217
+
218
+ ```ruby
219
+ messages = RubyCanUseLLM::Prompt.load("prompts/commodity_analysis.yml",
220
+ domain: "electronics",
221
+ description: "capacitor 10uF",
222
+ references: ["ceramic", "electrolytic"]
223
+ )
224
+ RubyCanUseLLM.chat(messages)
225
+ ```
226
+
227
+ For inline prompts:
228
+
229
+ ```ruby
230
+ prompt = RubyCanUseLLM::Prompt.new(
231
+ system: "You are a <%= role %> assistant.",
232
+ user: "Help me with: <%= task %>"
233
+ )
234
+ messages = prompt.render(role: "coding", task: "fix this bug")
235
+ RubyCanUseLLM.chat(messages)
236
+ ```
237
+
238
+ ERB is supported in both cases — loops, conditionals, any Ruby expression.
239
+
200
240
  ## Generators
201
241
 
202
242
  | Command | Description |
203
243
  |---------|-------------|
204
244
  | `rubycanusellm generate:config` | Configuration file with provider setup |
205
245
  | `rubycanusellm generate:completion` | Completion service object |
246
+ | `rubycanusellm generate:embedding` | Embedding service object |
206
247
 
207
248
  ## Roadmap
208
249
 
@@ -219,6 +260,7 @@ end
219
260
  - [x] Mistral provider (chat + embeddings)
220
261
  - [x] Ollama provider (chat + embeddings, local)
221
262
  - [x] `generate:embedding` command
263
+ - [x] Prompt templates (ERB + YAML file-based)
222
264
  - [ ] Tool calling
223
265
 
224
266
  ## Development
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "erb"
4
+ require "yaml"
5
+
6
+ module RubyCanUseLLM
7
+ class Prompt
8
+ VALID_ROLES = %w[system user assistant].freeze
9
+
10
+ def initialize(**roles)
11
+ invalid = roles.keys.map(&:to_s) - VALID_ROLES
12
+ unless invalid.empty?
13
+ raise Error, "Invalid role(s): #{invalid.join(", ")}. Valid roles: #{VALID_ROLES.join(", ")}"
14
+ end
15
+ if !roles.key?(:user) && !roles.key?("user")
16
+ raise Error, "Prompt requires at least a :user role"
17
+ end
18
+
19
+ @roles = roles.transform_keys(&:to_sym)
20
+ end
21
+
22
+ def self.load(path, **variables)
23
+ raise Error, "Prompt file not found: #{path}" unless File.exist?(path)
24
+
25
+ data = YAML.safe_load(File.read(path))
26
+ unless data.is_a?(Hash)
27
+ raise Error, "Prompt file must be a YAML hash with role keys (system, user, assistant)"
28
+ end
29
+
30
+ roles = data.transform_keys(&:to_sym).slice(*VALID_ROLES.map(&:to_sym))
31
+ new(**roles).render(**variables)
32
+ end
33
+
34
+ def render(**variables)
35
+ binding_obj = build_binding(variables)
36
+ @roles.filter_map do |role, template|
37
+ next if template.nil? || template.strip.empty?
38
+ content = ERB.new(template, trim_mode: "-").result(binding_obj)
39
+ { role: role, content: content.strip }
40
+ end
41
+ rescue NameError => e
42
+ raise Error, "Missing variable in prompt template: #{e.message}"
43
+ end
44
+
45
+ private
46
+
47
+ def build_binding(variables)
48
+ ctx = Object.new
49
+ variables.each do |key, value|
50
+ ctx.define_singleton_method(key) { value }
51
+ end
52
+ ctx.instance_eval { binding }
53
+ end
54
+ end
55
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rubycanusellm
4
- VERSION = "0.4.1"
4
+ VERSION = "0.5.0"
5
5
  end
data/lib/rubycanusellm.rb CHANGED
@@ -12,6 +12,7 @@ require_relative "rubycanusellm/providers/voyage"
12
12
  require_relative "rubycanusellm/providers/mistral"
13
13
  require_relative "rubycanusellm/providers/ollama"
14
14
  require_relative "rubycanusellm/embedding_response"
15
+ require_relative "rubycanusellm/prompt"
15
16
 
16
17
  module RubyCanUseLLM
17
18
  PROVIDERS = {
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubycanusellm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Juan Manuel Guzman Nava
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-04-03 00:00:00.000000000 Z
11
+ date: 2026-04-04 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: One interface, every LLM. Rubycanusellm provides a unified client for
14
14
  OpenAI, Anthropic, and more, plus generators that scaffold the boilerplate so you
@@ -33,6 +33,7 @@ files:
33
33
  - lib/rubycanusellm/configuration.rb
34
34
  - lib/rubycanusellm/embedding_response.rb
35
35
  - lib/rubycanusellm/errors.rb
36
+ - lib/rubycanusellm/prompt.rb
36
37
  - lib/rubycanusellm/providers/anthropic.rb
37
38
  - lib/rubycanusellm/providers/base.rb
38
39
  - lib/rubycanusellm/providers/mistral.rb