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 +4 -4
- data/CHANGELOG.md +10 -0
- data/lib/legion/cli/prompt_command.rb +136 -0
- data/lib/legion/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 72bd61b58a41c643d7570541ccd32493cc6357e32db64c3649275d7b7a1c159f
|
|
4
|
+
data.tar.gz: 05b98ee5d6ee262bdb7909842c827d43f73bca4bc245cfb4e3e453a57939d45c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
data/lib/legion/version.rb
CHANGED