legionio 1.4.60 → 1.4.61
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 +11 -0
- data/CLAUDE.md +2 -2
- data/lib/legion/cli/chat/subagent.rb +20 -3
- data/lib/legion/cli/chat_command.rb +39 -15
- data/lib/legion/cli/config_scaffold.rb +27 -1
- 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: 6c7e2aaea33b6be8c15f2059d61621a70e9e431957e4e574b8ff574d33d40045
|
|
4
|
+
data.tar.gz: 07ea8f95f7b2c5132f8fe7992ccb247d5cec1fe909f3ba927f42bf172fff22ec
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a5648ed88592cb9eaaac03a285f3862812ff9dbd93ea3a0f8a2bd1ff400e7b2084c3d59e5b2b5fbbf0016ff05f4897291f25f59b62c543ef86b9806aeba6a377
|
|
7
|
+
data.tar.gz: 73b80071c84f14627df14ceca94a9f7201143ca47149244838d649387d82430cfffaf3a1998fcb92f91d6aecc73abc9a8ce151eb6ea626c8237b738554ca9965
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Legion Changelog
|
|
2
2
|
|
|
3
|
+
## [1.4.61] - 2026-03-18
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- Chat persistent settings defaults via `Legion::Settings` (issue #5)
|
|
7
|
+
- `chat_setting(*keys)` helper for centralized settings access with error handling
|
|
8
|
+
- Settings priority chain: CLI flag > `Legion::Settings.dig(:chat, ...)` > hardcoded default
|
|
9
|
+
- Configurable via settings: model, provider, personality, permissions, markdown, incognito, max_budget_usd, subagent concurrency/timeout, headless max_turns
|
|
10
|
+
- `chat` subsystem added to `config scaffold` with full template
|
|
11
|
+
- `Subagent.configure_from_settings` reads concurrency and timeout from settings
|
|
12
|
+
- 22 new specs (19 settings integration + 3 subagent settings)
|
|
13
|
+
|
|
3
14
|
## [1.4.60] - 2026-03-18
|
|
4
15
|
|
|
5
16
|
### Fixed
|
data/CLAUDE.md
CHANGED
|
@@ -9,7 +9,7 @@ The primary gem for the LegionIO framework. An extensible async job engine for s
|
|
|
9
9
|
|
|
10
10
|
**GitHub**: https://github.com/LegionIO/LegionIO
|
|
11
11
|
**Gem**: `legionio`
|
|
12
|
-
**Version**: 1.4.
|
|
12
|
+
**Version**: 1.4.61
|
|
13
13
|
**License**: Apache-2.0
|
|
14
14
|
**Docker**: `legionio/legion`
|
|
15
15
|
**Ruby**: >= 3.4
|
|
@@ -711,7 +711,7 @@ rack-test, rake, rspec, rubocop, rubocop-rspec, simplecov
|
|
|
711
711
|
|
|
712
712
|
```bash
|
|
713
713
|
bundle install
|
|
714
|
-
bundle exec rspec #
|
|
714
|
+
bundle exec rspec # 1379 examples, 0 failures
|
|
715
715
|
bundle exec rubocop # 396 files, 0 offenses
|
|
716
716
|
```
|
|
717
717
|
|
|
@@ -13,15 +13,32 @@ module Legion
|
|
|
13
13
|
@running = []
|
|
14
14
|
@mutex = Mutex.new
|
|
15
15
|
@max_concurrency = MAX_CONCURRENCY
|
|
16
|
+
@timeout = TIMEOUT
|
|
16
17
|
|
|
17
18
|
class << self
|
|
18
|
-
attr_accessor :max_concurrency
|
|
19
|
+
attr_accessor :max_concurrency, :timeout
|
|
19
20
|
|
|
20
|
-
def configure(max_concurrency: MAX_CONCURRENCY)
|
|
21
|
+
def configure(max_concurrency: MAX_CONCURRENCY, timeout: TIMEOUT)
|
|
21
22
|
@max_concurrency = max_concurrency
|
|
23
|
+
@timeout = timeout
|
|
22
24
|
@running = []
|
|
23
25
|
end
|
|
24
26
|
|
|
27
|
+
def configure_from_settings
|
|
28
|
+
mc = begin
|
|
29
|
+
Legion::Settings.dig(:chat, :subagent, :max_concurrency)
|
|
30
|
+
rescue StandardError
|
|
31
|
+
nil
|
|
32
|
+
end
|
|
33
|
+
to = begin
|
|
34
|
+
Legion::Settings.dig(:chat, :subagent, :timeout)
|
|
35
|
+
rescue StandardError
|
|
36
|
+
nil
|
|
37
|
+
end
|
|
38
|
+
@max_concurrency = mc || MAX_CONCURRENCY
|
|
39
|
+
@timeout = to || TIMEOUT
|
|
40
|
+
end
|
|
41
|
+
|
|
25
42
|
def spawn(task:, model: nil, provider: nil, on_complete: nil)
|
|
26
43
|
return { error: "Max concurrency reached (#{@max_concurrency}). Wait for a subagent to finish." } if at_capacity?
|
|
27
44
|
|
|
@@ -54,7 +71,7 @@ module Legion
|
|
|
54
71
|
@mutex.synchronize { @running.length >= @max_concurrency }
|
|
55
72
|
end
|
|
56
73
|
|
|
57
|
-
def wait_all(timeout: TIMEOUT)
|
|
74
|
+
def wait_all(timeout: @timeout || TIMEOUT)
|
|
58
75
|
deadline = Time.now + timeout
|
|
59
76
|
@running.each do |agent|
|
|
60
77
|
remaining = deadline - Time.now
|
|
@@ -45,7 +45,7 @@ module Legion
|
|
|
45
45
|
system_prompt = build_system_prompt
|
|
46
46
|
@session = Chat::Session.new(
|
|
47
47
|
chat: chat_obj, system_prompt: system_prompt,
|
|
48
|
-
budget_usd:
|
|
48
|
+
budget_usd: effective_budget
|
|
49
49
|
)
|
|
50
50
|
@indicator = Chat::StatusIndicator.new(@session) unless options[:json]
|
|
51
51
|
|
|
@@ -55,7 +55,7 @@ module Legion
|
|
|
55
55
|
|
|
56
56
|
setup_notification_bridge
|
|
57
57
|
|
|
58
|
-
chat_log.info "session started model=#{@session.model_id} incognito=#{
|
|
58
|
+
chat_log.info "session started model=#{@session.model_id} incognito=#{incognito?}"
|
|
59
59
|
out.banner(version: Legion::VERSION)
|
|
60
60
|
puts
|
|
61
61
|
puts out.dim(" Model: #{@session.model_id}")
|
|
@@ -80,7 +80,7 @@ module Legion
|
|
|
80
80
|
|
|
81
81
|
desc 'prompt TEXT', 'Send a single prompt and exit (headless mode)'
|
|
82
82
|
option :output_format, type: :string, default: 'text', desc: 'Output format: text, json'
|
|
83
|
-
option :max_turns, type: :numeric,
|
|
83
|
+
option :max_turns, type: :numeric, desc: 'Maximum tool-use turns (default: 10)'
|
|
84
84
|
def prompt(text)
|
|
85
85
|
out = formatter
|
|
86
86
|
setup_chat_logger
|
|
@@ -94,7 +94,7 @@ module Legion
|
|
|
94
94
|
system_prompt = build_system_prompt
|
|
95
95
|
session = Chat::Session.new(
|
|
96
96
|
chat: chat_obj, system_prompt: system_prompt,
|
|
97
|
-
budget_usd:
|
|
97
|
+
budget_usd: effective_budget
|
|
98
98
|
)
|
|
99
99
|
|
|
100
100
|
chat_log.info "headless prompt model=#{session.model_id} length=#{text.length}"
|
|
@@ -129,6 +129,24 @@ module Legion
|
|
|
129
129
|
end
|
|
130
130
|
|
|
131
131
|
no_commands do
|
|
132
|
+
def chat_setting(*keys)
|
|
133
|
+
Legion::Settings.dig(:chat, *keys)
|
|
134
|
+
rescue StandardError
|
|
135
|
+
nil
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def incognito?
|
|
139
|
+
options[:incognito] || chat_setting(:incognito) == true
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def effective_budget
|
|
143
|
+
options[:max_budget_usd] || chat_setting(:max_budget_usd)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def effective_max_turns
|
|
147
|
+
options[:max_turns] || chat_setting(:headless, :max_turns) || 10
|
|
148
|
+
end
|
|
149
|
+
|
|
132
150
|
def formatter
|
|
133
151
|
@formatter ||= Output::Formatter.new(
|
|
134
152
|
json: options[:json],
|
|
@@ -173,7 +191,12 @@ module Legion
|
|
|
173
191
|
end
|
|
174
192
|
|
|
175
193
|
def render_response(text, out)
|
|
176
|
-
|
|
194
|
+
markdown_enabled = if options[:no_markdown]
|
|
195
|
+
false
|
|
196
|
+
else
|
|
197
|
+
chat_setting(:markdown) != false
|
|
198
|
+
end
|
|
199
|
+
return text unless markdown_enabled && out.color_enabled
|
|
177
200
|
|
|
178
201
|
require 'legion/cli/chat/markdown_renderer'
|
|
179
202
|
Chat::MarkdownRenderer.render(text, color: out.color_enabled)
|
|
@@ -194,6 +217,8 @@ module Legion
|
|
|
194
217
|
require 'legion/cli/chat/permissions'
|
|
195
218
|
Chat::Permissions.mode = if options[:auto_approve]
|
|
196
219
|
:auto_approve
|
|
220
|
+
elsif (setting = chat_setting(:permissions))
|
|
221
|
+
setting.to_sym
|
|
197
222
|
else
|
|
198
223
|
default
|
|
199
224
|
end
|
|
@@ -201,8 +226,9 @@ module Legion
|
|
|
201
226
|
|
|
202
227
|
def create_chat
|
|
203
228
|
opts = {}
|
|
204
|
-
opts[:model] = options[:model]
|
|
205
|
-
opts[:provider] = options[:provider]
|
|
229
|
+
opts[:model] = options[:model] || chat_setting(:model)
|
|
230
|
+
opts[:provider] = (options[:provider] || chat_setting(:provider))&.to_sym
|
|
231
|
+
opts.compact!
|
|
206
232
|
|
|
207
233
|
require 'legion/cli/chat/tool_registry'
|
|
208
234
|
chat = Legion::LLM.chat(**opts)
|
|
@@ -217,13 +243,11 @@ module Legion
|
|
|
217
243
|
@extra_dirs = options[:add_dir] || []
|
|
218
244
|
prompt = Chat::Context.to_system_prompt(Dir.pwd, extra_dirs: @extra_dirs)
|
|
219
245
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
when 'educational' then prompt += "\n\nBe educational. Explain concepts, provide context, teach as you help."
|
|
226
|
-
end
|
|
246
|
+
@personality = options[:personality] || chat_setting(:personality)
|
|
247
|
+
case @personality
|
|
248
|
+
when 'concise' then prompt += "\n\nBe extremely concise. Short answers, minimal explanation. Code over prose."
|
|
249
|
+
when 'verbose' then prompt += "\n\nBe thorough and detailed. Explain your reasoning step by step."
|
|
250
|
+
when 'educational' then prompt += "\n\nBe educational. Explain concepts, provide context, teach as you help."
|
|
227
251
|
end
|
|
228
252
|
|
|
229
253
|
prompt
|
|
@@ -1014,7 +1038,7 @@ module Legion
|
|
|
1014
1038
|
|
|
1015
1039
|
def auto_save_session(out)
|
|
1016
1040
|
return if @auto_saved
|
|
1017
|
-
return if
|
|
1041
|
+
return if incognito?
|
|
1018
1042
|
return unless @session
|
|
1019
1043
|
return if @session.stats[:messages_sent].zero?
|
|
1020
1044
|
|
|
@@ -7,7 +7,7 @@ require 'net/http'
|
|
|
7
7
|
module Legion
|
|
8
8
|
module CLI
|
|
9
9
|
module ConfigScaffold
|
|
10
|
-
SUBSYSTEMS = %w[transport data cache crypt logging llm].freeze
|
|
10
|
+
SUBSYSTEMS = %w[transport data cache crypt logging llm chat].freeze
|
|
11
11
|
|
|
12
12
|
ENV_DETECTIONS = {
|
|
13
13
|
'AWS_BEARER_TOKEN_BEDROCK' => { subsystem: 'llm', provider: :bedrock, field: :bearer_token },
|
|
@@ -202,6 +202,19 @@ module Legion
|
|
|
202
202
|
ollama: { enabled: false, base_url: 'http://localhost:11434' }
|
|
203
203
|
}
|
|
204
204
|
} }
|
|
205
|
+
when 'chat'
|
|
206
|
+
{ chat: {
|
|
207
|
+
permissions: 'interactive',
|
|
208
|
+
model: nil,
|
|
209
|
+
provider: nil,
|
|
210
|
+
personality: nil,
|
|
211
|
+
markdown: true,
|
|
212
|
+
incognito: false,
|
|
213
|
+
max_budget_usd: nil,
|
|
214
|
+
subagent: { max_concurrency: 3, timeout: 300 },
|
|
215
|
+
headless: { max_turns: 10 },
|
|
216
|
+
notifications: { patterns: [] }
|
|
217
|
+
} }
|
|
205
218
|
end
|
|
206
219
|
end
|
|
207
220
|
|
|
@@ -344,6 +357,19 @@ module Legion
|
|
|
344
357
|
ollama: { enabled: false, base_url: 'http://localhost:11434' }
|
|
345
358
|
}
|
|
346
359
|
} }
|
|
360
|
+
when 'chat'
|
|
361
|
+
{ chat: {
|
|
362
|
+
permissions: 'interactive',
|
|
363
|
+
model: nil,
|
|
364
|
+
provider: nil,
|
|
365
|
+
personality: nil,
|
|
366
|
+
markdown: true,
|
|
367
|
+
incognito: false,
|
|
368
|
+
max_budget_usd: nil,
|
|
369
|
+
subagent: { max_concurrency: 3, timeout: 300 },
|
|
370
|
+
headless: { max_turns: 10 },
|
|
371
|
+
notifications: { patterns: [] }
|
|
372
|
+
} }
|
|
347
373
|
end
|
|
348
374
|
end
|
|
349
375
|
end
|
data/lib/legion/version.rb
CHANGED