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 +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +42 -0
- data/lib/rubycanusellm/prompt.rb +55 -0
- data/lib/rubycanusellm/version.rb +1 -1
- data/lib/rubycanusellm.rb +1 -0
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8366062327382434c0f86c1cb30a0a2265b1d26e7e512b294884aeac93e09468
|
|
4
|
+
data.tar.gz: 510d3d9d0051a4cdcb63ecdf7e0d1f4e536e27701a64504cd57fb555868aba1d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
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
|
+
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-
|
|
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
|