legionio 1.4.93 → 1.4.94

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: 318839858d16ecbaaf6c7db4a0d9562e1641ca24d174fda914b9d359f3f91e69
4
- data.tar.gz: 91e1415070e2f547bc7c71646e79312f048f8973b2cb004045a8d546a0000387
3
+ metadata.gz: 72bd61b58a41c643d7570541ccd32493cc6357e32db64c3649275d7b7a1c159f
4
+ data.tar.gz: 05b98ee5d6ee262bdb7909842c827d43f73bca4bc245cfb4e3e453a57939d45c
5
5
  SHA512:
6
- metadata.gz: e5cd6e2ff71cc11db2a1e8928aae0c53104f931c18829bf470658bbcac3e2f90a18aeb7c564dcc7eb3f113fa9c65b54bb165a0f322fc3b1021a0ebf98148bf66
7
- data.tar.gz: ff3c9e796fef50d7ca2e7b1970c4516a2d839031f8bee6036fc43b758f0035d85b5bc80fd631c5e55d8a83ce28fe5a7ccfa55fa69b67237b868331d1606d3d34
6
+ metadata.gz: c339580f9b229475d21752fa56bfcb90c7213c177dd83dc713220e1d872dbbe13ad690122abc5f4c620416a45bbda960c11dc355fe048b756ea5224259576647
7
+ data.tar.gz: 2f738e376dc5b147a8e3b4dcc71013fce20cc39b1ec24bbdac922080df327be7f8f743e860a62ee21ab6b935b0d9e7d23b48703adc1ccf274bf5ff713d4f90b3
data/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Legion Changelog
2
2
 
3
+ ## [1.4.94] - 2026-03-20
4
+
5
+ ### Added
6
+ - `legion prompt play NAME` subcommand: renders a prompt template with variables and sends it to an LLM via `Legion::LLM.chat`
7
+ - `--variables` (JSON), `--version`, `--model`, `--provider`, and `--compare` options on `play`
8
+ - Compare mode (`--compare VERSION`): renders two prompt versions, calls LLM for each, displays side-by-side responses and diff when they differ
9
+ - JSON output mode for `play` and compare via `--json`
10
+ - `Connection.ensure_llm` called inside `with_prompt_client` so LLM is available to all prompt subcommands
11
+ - 14 new specs for `play` covering single-version, compare, LLM unavailable, JSON output, and error paths
12
+
3
13
  ## [1.4.93] - 2026-03-20
4
14
 
5
15
  ### Added
@@ -140,6 +140,36 @@ module Legion
140
140
  end
141
141
  end
142
142
 
143
+ desc 'play NAME', 'Run a prompt through an LLM and display the response'
144
+ option :variables, type: :string, desc: 'Template variables as JSON'
145
+ option :version, type: :numeric, desc: 'Prompt version'
146
+ option :model, type: :string, desc: 'LLM model override'
147
+ option :provider, type: :string, desc: 'LLM provider override'
148
+ option :compare, type: :numeric, desc: 'Compare with this version'
149
+ def play(name)
150
+ out = formatter
151
+ with_prompt_client do |client|
152
+ unless defined?(Legion::LLM) && Legion::LLM.started?
153
+ out.error('legion-llm is not available. Install legion-llm and configure a provider.')
154
+ raise SystemExit, 1
155
+ end
156
+
157
+ vars = parse_variables(options[:variables], out)
158
+ return if vars.nil?
159
+
160
+ llm_kwargs = {}
161
+ llm_kwargs[:model] = options[:model] if options[:model]
162
+ llm_kwargs[:provider] = options[:provider] if options[:provider]
163
+
164
+ base_ctx = { name: name, vars: vars, llm_kwargs: llm_kwargs, client: client, out: out }
165
+ if options[:compare]
166
+ run_compare(base_ctx.merge(ver_a: options[:version], ver_b: options[:compare]))
167
+ else
168
+ run_single(base_ctx.merge(version: options[:version]))
169
+ end
170
+ end
171
+ end
172
+
143
173
  no_commands do
144
174
  def formatter
145
175
  @formatter ||= Output::Formatter.new(
@@ -152,6 +182,7 @@ module Legion
152
182
  Connection.config_dir = options[:config_dir] if options[:config_dir]
153
183
  Connection.log_level = options[:verbose] ? 'debug' : 'error'
154
184
  Connection.ensure_data
185
+ Connection.ensure_llm
155
186
 
156
187
  begin
157
188
  require 'legion/extensions/prompt'
@@ -181,6 +212,15 @@ module Legion
181
212
  nil
182
213
  end
183
214
 
215
+ def parse_variables(raw, out)
216
+ return {} if raw.nil? || raw.empty?
217
+
218
+ ::JSON.parse(raw)
219
+ rescue ::JSON::ParserError => e
220
+ out.error("Invalid JSON for --variables: #{e.message}")
221
+ nil
222
+ end
223
+
184
224
  def diff_lines(old_text, new_text)
185
225
  old_lines = old_text.split("\n")
186
226
  new_lines = new_text.split("\n")
@@ -191,6 +231,102 @@ module Legion
191
231
  new_lines.each { |l| result << "+ #{l}" unless old_set.include?(l) }
192
232
  result.join("\n")
193
233
  end
234
+
235
+ def run_single(ctx)
236
+ name, version, vars, llm_kwargs, client, out = ctx.values_at(:name, :version, :vars, :llm_kwargs, :client, :out)
237
+ prompt = fetch_prompt(name, version, client, out)
238
+ return if prompt.nil?
239
+
240
+ rendered = render_prompt(name, version, vars, client, out)
241
+ return if rendered.nil?
242
+
243
+ response = Legion::LLM.chat(
244
+ messages: [{ role: 'user', content: rendered }],
245
+ **llm_kwargs
246
+ )
247
+
248
+ if options[:json]
249
+ out.json({ name: name, version: prompt[:version], rendered: rendered,
250
+ response: response[:content], usage: response[:usage] })
251
+ else
252
+ out.header("Prompt: #{name} (v#{prompt[:version]})")
253
+ out.spacer
254
+ out.header('Rendered Template')
255
+ puts rendered
256
+ out.spacer
257
+ out.header('LLM Response')
258
+ puts response[:content]
259
+ display_usage(response[:usage], out)
260
+ end
261
+ end
262
+
263
+ def run_compare(ctx)
264
+ name, ver_a, ver_b, vars, llm_kwargs, client, out =
265
+ ctx.values_at(:name, :ver_a, :ver_b, :vars, :llm_kwargs, :client, :out)
266
+ prompt_a = fetch_prompt(name, ver_a, client, out)
267
+ return if prompt_a.nil?
268
+
269
+ prompt_b = fetch_prompt(name, ver_b, client, out)
270
+ return if prompt_b.nil?
271
+
272
+ rendered_a = render_prompt(name, prompt_a[:version], vars, client, out)
273
+ return if rendered_a.nil?
274
+
275
+ rendered_b = render_prompt(name, prompt_b[:version], vars, client, out)
276
+ return if rendered_b.nil?
277
+
278
+ response_a = Legion::LLM.chat(messages: [{ role: 'user', content: rendered_a }], **llm_kwargs)
279
+ response_b = Legion::LLM.chat(messages: [{ role: 'user', content: rendered_b }], **llm_kwargs)
280
+
281
+ if options[:json]
282
+ out.json({ name: name, version_a: prompt_a[:version], version_b: prompt_b[:version],
283
+ rendered_a: rendered_a, rendered_b: rendered_b,
284
+ response_a: response_a[:content], response_b: response_b[:content],
285
+ usage_a: response_a[:usage], usage_b: response_b[:usage] })
286
+ else
287
+ out.header("Version A (v#{prompt_a[:version]})")
288
+ puts response_a[:content]
289
+ out.spacer
290
+ out.header("Version B (v#{prompt_b[:version]})")
291
+ puts response_b[:content]
292
+ content_a = response_a[:content].to_s
293
+ content_b = response_b[:content].to_s
294
+ if content_a != content_b
295
+ out.spacer
296
+ out.header('Diff (A vs B)')
297
+ puts diff_lines(content_a, content_b)
298
+ end
299
+ end
300
+ end
301
+
302
+ def fetch_prompt(name, version, client, out)
303
+ kwargs = { name: name }
304
+ kwargs[:version] = version if version
305
+ result = client.get_prompt(**kwargs)
306
+ if result[:error]
307
+ out.error("Prompt '#{name}': #{result[:error]}")
308
+ raise SystemExit, 1
309
+ end
310
+ result
311
+ end
312
+
313
+ def render_prompt(name, version, vars, client, out)
314
+ kwargs = { name: name, variables: vars }
315
+ kwargs[:version] = version if version
316
+ result = client.render_prompt(**kwargs)
317
+ if result.is_a?(Hash) && result[:error]
318
+ out.error("Render error for '#{name}': #{result[:error]}")
319
+ raise SystemExit, 1
320
+ end
321
+ result.is_a?(Hash) ? result[:rendered] : result
322
+ end
323
+
324
+ def display_usage(usage, out)
325
+ return unless usage && !usage.empty?
326
+
327
+ out.spacer
328
+ out.detail(usage)
329
+ end
194
330
  end
195
331
  end
196
332
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Legion
4
- VERSION = '1.4.93'
4
+ VERSION = '1.4.94'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: legionio
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.93
4
+ version: 1.4.94
5
5
  platform: ruby
6
6
  authors:
7
7
  - Esity