lemans 1.0.0.pre.1 → 1.0.0.rc.2
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 +1 -5
- data/README.md +47 -28
- data/exe/lemans-remote +43 -41
- data/lib/lemans/agents/miniswen_installed.rb +4 -4
- data/lib/lemans/cli/board_reporter.rb +8 -8
- data/lib/lemans/cli/progress_reporter.rb +1 -1
- data/lib/lemans/cli/report/aggregate.rb +2 -2
- data/lib/lemans/cli/report.rb +6 -6
- data/lib/lemans/cli/templates/bench/README.md +41 -0
- data/lib/lemans/cli/templates/bench/bench.yml +108 -0
- data/lib/lemans/cli/templates/bench/environment/Dockerfile +10 -0
- data/lib/lemans/cli/templates/bench/tasks/example-task/environment.patch +7 -0
- data/lib/lemans/cli/templates/bench/tasks/example-task/instruction.md +32 -0
- data/lib/lemans/cli/templates/bench/tasks/example-task/solution.patch +7 -0
- data/lib/lemans/cli/templates/bench/tasks/example-task/verification_test.rb +34 -0
- data/lib/lemans/cli/templates/bench/tasks/hello-world/environment.patch +7 -0
- data/lib/lemans/cli/templates/bench/tasks/hello-world/instruction.md +11 -0
- data/lib/lemans/cli/templates/bench/tasks/hello-world/solution.patch +7 -0
- data/lib/lemans/cli/templates/bench/tasks/hello-world/verification_test.rb +10 -0
- data/lib/lemans/cli.rb +14 -3
- data/lib/lemans/config/environment.rb +5 -1
- data/lib/lemans/config/revision.rb +2 -0
- data/lib/lemans/config/setup.rb +1 -15
- data/lib/lemans/config/tree_digest.rb +1 -1
- data/lib/lemans/config/verifier.rb +1 -1
- data/lib/lemans/config.rb +8 -0
- data/lib/lemans/environments/daytona/faraday_transfer.rb +1 -1
- data/lib/lemans/environments/daytona/retries.rb +1 -1
- data/lib/lemans/environments/daytona/sdk_tweaks.rb +2 -2
- data/lib/lemans/environments/daytona/shell.rb +1 -1
- data/lib/lemans/environments/daytona/snapshot_store.rb +2 -2
- data/lib/lemans/environments/daytona.rb +1 -1
- data/lib/lemans/result.rb +1 -1
- data/lib/lemans/secrets_filter.rb +25 -0
- data/lib/lemans/stores/fs.rb +17 -4
- data/lib/lemans/task_definition.rb +10 -8
- data/lib/lemans/trial/verifier/assets/eport-lemans.rb +9 -1
- data/lib/lemans/trial/verifier/assets/lemans_minitest_reporter.rb +2 -2
- data/lib/lemans/trial/verifier.rb +3 -3
- data/lib/lemans/trial.rb +1 -1
- data/lib/lemans/version.rb +1 -1
- data/lib/lemans.rb +2 -0
- data/lib/miniswen/agent.rb +11 -11
- data/lib/miniswen/ruby_llm.rb +7 -1
- data/lib/miniswen/testing.rb +7 -7
- data/lib/miniswen/trajectory.rb +1 -1
- data/lib/miniswen/version.rb +1 -1
- metadata +15 -1
|
@@ -64,8 +64,8 @@ module Lemans
|
|
|
64
64
|
def upload_tests!
|
|
65
65
|
environment.exec!("rm -rf #{TESTS_DIR} && mkdir -p #{TESTS_DIR}")
|
|
66
66
|
|
|
67
|
-
uploads = task.verifier.files.to_h { |local, remote| [remote, local] }
|
|
68
|
-
.merge(task.test_files.to_h { |local, remote| [remote, local] })
|
|
67
|
+
uploads = task.verifier.files.to_h { |local, remote| [ remote, local ] }
|
|
68
|
+
.merge(task.test_files.to_h { |local, remote| [ remote, local ] })
|
|
69
69
|
|
|
70
70
|
uploads.each { |remote, local| environment.upload(local, "#{TESTS_DIR}/#{remote}") }
|
|
71
71
|
ASSETS.glob("*.rb").each { |asset| environment.upload(asset, "#{TESTS_DIR}/#{asset.basename}") }
|
|
@@ -102,7 +102,7 @@ module Lemans
|
|
|
102
102
|
end
|
|
103
103
|
|
|
104
104
|
def verifier_script
|
|
105
|
-
[task.verifier.preverify, task.verifier.command].compact.map { "( #{it} )" }.join(" && ")
|
|
105
|
+
[ task.verifier.preverify, task.verifier.command ].compact.map { "( #{it} )" }.join(" && ")
|
|
106
106
|
end
|
|
107
107
|
|
|
108
108
|
def read_reward(command_result)
|
data/lib/lemans/trial.rb
CHANGED
|
@@ -118,7 +118,7 @@ module Lemans
|
|
|
118
118
|
raise
|
|
119
119
|
rescue StandardError => e
|
|
120
120
|
# A harness bug must leave evidence.
|
|
121
|
-
result.failed!(:harness_crash, ["#{e.class}: #{e.message}", *Array(e.backtrace).first(5)].join("\n"))
|
|
121
|
+
result.failed!(:harness_crash, [ "#{e.class}: #{e.message}", *Array(e.backtrace).first(5) ].join("\n"))
|
|
122
122
|
ensure
|
|
123
123
|
environment&.stop
|
|
124
124
|
end
|
data/lib/lemans/version.rb
CHANGED
data/lib/lemans.rb
CHANGED
|
@@ -9,6 +9,8 @@ loader.inflector.inflect("cli" => "CLI", "atif" => "ATIF", "fs" => "FS",
|
|
|
9
9
|
loader.ignore("#{__dir__}/miniswen.rb", "#{__dir__}/miniswen")
|
|
10
10
|
# assets/ holds files uploaded into sandboxes, not Ruby the harness loads.
|
|
11
11
|
loader.ignore("#{__dir__}/lemans/trial/verifier/assets")
|
|
12
|
+
# templates/ holds the files `lemans init` scaffolds, not Ruby the harness loads.
|
|
13
|
+
loader.ignore("#{__dir__}/lemans/cli/templates")
|
|
12
14
|
loader.setup
|
|
13
15
|
|
|
14
16
|
require "miniswen"
|
data/lib/miniswen/agent.rb
CHANGED
|
@@ -215,9 +215,9 @@ module Miniswen
|
|
|
215
215
|
value.to_h do |key, item|
|
|
216
216
|
key = key.to_sym
|
|
217
217
|
# Tool-call arguments and reasoning details keep their provider-style string keys.
|
|
218
|
-
[key, %i[arguments reasoning_details].include?(key) ? item : deep_symbolize(item)]
|
|
218
|
+
[ key, %i[arguments reasoning_details].include?(key) ? item : deep_symbolize(item) ]
|
|
219
219
|
end
|
|
220
|
-
when Array then value.map { deep_symbolize(
|
|
220
|
+
when Array then value.map { deep_symbolize(it) }
|
|
221
221
|
else value
|
|
222
222
|
end
|
|
223
223
|
end
|
|
@@ -313,7 +313,7 @@ module Miniswen
|
|
|
313
313
|
# them back from ENV on boot (the option upcased).
|
|
314
314
|
def provider_env
|
|
315
315
|
_, provider = resolved
|
|
316
|
-
env = provider.configuration_requirements.to_h { [
|
|
316
|
+
env = provider.configuration_requirements.to_h { [ it.to_s.upcase, RubyLLM.config.public_send(it) ] }.compact
|
|
317
317
|
|
|
318
318
|
order = ENV["LEMANS_PROVIDER_ORDER"]
|
|
319
319
|
env["LEMANS_PROVIDER_ORDER"] = order if order
|
|
@@ -340,7 +340,7 @@ module Miniswen
|
|
|
340
340
|
def next_actions
|
|
341
341
|
response = complete(@messages)
|
|
342
342
|
@steps += 1
|
|
343
|
-
@totals.each_key { @totals[
|
|
343
|
+
@totals.each_key { @totals[it] += response[it].to_i }
|
|
344
344
|
track_cost(response)
|
|
345
345
|
|
|
346
346
|
entry = { role: "assistant", timestamp: Time.now.utc.iso8601, content: response[:content].to_s,
|
|
@@ -496,7 +496,7 @@ module Miniswen
|
|
|
496
496
|
def complete(messages)
|
|
497
497
|
model_info, provider = resolved
|
|
498
498
|
response = provider.complete(
|
|
499
|
-
with_cache_breakpoints(messages.map { as_ruby_llm(
|
|
499
|
+
with_cache_breakpoints(messages.map { as_ruby_llm(it) }),
|
|
500
500
|
tools: { bash: @bash_tool },
|
|
501
501
|
temperature: nil,
|
|
502
502
|
model: model_info,
|
|
@@ -518,13 +518,13 @@ module Miniswen
|
|
|
518
518
|
def with_cache_breakpoints(messages)
|
|
519
519
|
return messages unless explicit_cache?
|
|
520
520
|
|
|
521
|
-
system = messages.find {
|
|
522
|
-
[system, messages.last].compact.uniq.each do |message|
|
|
521
|
+
system = messages.find { it.role == :system }
|
|
522
|
+
[ system, messages.last ].compact.uniq.each do |message|
|
|
523
523
|
text = message.content
|
|
524
524
|
next unless text.is_a?(String) && !text.empty?
|
|
525
525
|
|
|
526
526
|
message.content = RubyLLM::Content::Raw.new(
|
|
527
|
-
[{ type: "text", text: text, cache_control: CACHE_CONTROL }]
|
|
527
|
+
[ { type: "text", text: text, cache_control: CACHE_CONTROL } ]
|
|
528
528
|
)
|
|
529
529
|
end
|
|
530
530
|
messages
|
|
@@ -580,8 +580,8 @@ module Miniswen
|
|
|
580
580
|
return nil if tool_calls.nil? || tool_calls.empty?
|
|
581
581
|
|
|
582
582
|
tool_calls.to_h do |call|
|
|
583
|
-
[call[:id], RubyLLM::ToolCall.new(id: call[:id], name: call[:name], arguments: call[:arguments],
|
|
584
|
-
thought_signature: call[:thought_signature])]
|
|
583
|
+
[ call[:id], RubyLLM::ToolCall.new(id: call[:id], name: call[:name], arguments: call[:arguments],
|
|
584
|
+
thought_signature: call[:thought_signature]) ]
|
|
585
585
|
end
|
|
586
586
|
end
|
|
587
587
|
|
|
@@ -668,7 +668,7 @@ module Miniswen
|
|
|
668
668
|
cache_write = info.cache_write_input_price_per_million || input
|
|
669
669
|
# Providers usually fold thinking into output_tokens; max() bills the
|
|
670
670
|
# larger count once and can never double-bill.
|
|
671
|
-
generated = [response.output_tokens.to_i, tokens&.thinking.to_i].max
|
|
671
|
+
generated = [ response.output_tokens.to_i, tokens&.thinking.to_i ].max
|
|
672
672
|
((response.input_tokens.to_i * input) +
|
|
673
673
|
(tokens&.cached.to_i * cache_read) +
|
|
674
674
|
(tokens&.cache_creation.to_i * cache_write) +
|
data/lib/miniswen/ruby_llm.rb
CHANGED
|
@@ -8,6 +8,12 @@ RubyLLM.configure do |config|
|
|
|
8
8
|
config.logger = Logger.new(IO::NULL) unless ENV["MINISWEN_DEBUG"] == "1"
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
+
# Increase retry window to handle egress network issues
|
|
12
|
+
RubyLLM.configure do |config|
|
|
13
|
+
config.max_retries = 3
|
|
14
|
+
config.retry_interval = 1
|
|
15
|
+
end
|
|
16
|
+
|
|
11
17
|
# ruby_llm reads no API keys from ENV on its own; the conventional variable is the provider's
|
|
12
18
|
# config option upcased.
|
|
13
19
|
RubyLLM.configure do |config|
|
|
@@ -34,7 +40,7 @@ module Miniswen
|
|
|
34
40
|
# ConnectionFailed retries ruby_llm already does; it only lists SSL errors
|
|
35
41
|
# as fatal.
|
|
36
42
|
module RetryTransientSSL
|
|
37
|
-
def retry_exceptions = super + [Faraday::SSLError]
|
|
43
|
+
def retry_exceptions = super + [ Faraday::SSLError ]
|
|
38
44
|
end
|
|
39
45
|
end
|
|
40
46
|
|
data/lib/miniswen/testing.rb
CHANGED
|
@@ -60,14 +60,14 @@ module Miniswen
|
|
|
60
60
|
end
|
|
61
61
|
|
|
62
62
|
def on(command, output, exit_code: 0)
|
|
63
|
-
@canned[command] = [exit_code, output]
|
|
63
|
+
@canned[command] = [ exit_code, output ]
|
|
64
64
|
end
|
|
65
65
|
|
|
66
66
|
def exec(command, timeout: nil, env: nil) # rubocop:disable Lint/UnusedMethodArgument
|
|
67
67
|
@commands << command
|
|
68
68
|
return result(0, command.delete_prefix("echo ")) if command.start_with?("echo ")
|
|
69
69
|
|
|
70
|
-
exit_code, output = @canned.fetch(command, [0, ""])
|
|
70
|
+
exit_code, output = @canned.fetch(command, [ 0, "" ])
|
|
71
71
|
result(exit_code, output)
|
|
72
72
|
end
|
|
73
73
|
|
|
@@ -87,7 +87,7 @@ module Miniswen
|
|
|
87
87
|
# and/or :content, plus optional overrides (:tool_calls, :finish_reason,
|
|
88
88
|
# :thinking, token counts). Overrides given here apply to every answer.
|
|
89
89
|
def stub_llm(*answers, **overrides)
|
|
90
|
-
RubyLLM::Test.stub_responses(*answers.map { llm_answer(
|
|
90
|
+
RubyLLM::Test.stub_responses(*answers.map { llm_answer(it, **overrides) })
|
|
91
91
|
end
|
|
92
92
|
|
|
93
93
|
def llm_answer(answer, **overrides)
|
|
@@ -115,15 +115,15 @@ module Miniswen
|
|
|
115
115
|
def raw_body_for(answer, calls)
|
|
116
116
|
choice = { "finish_reason" => answer.fetch(:finish_reason) { calls.empty? ? "stop" : "tool_calls" } }
|
|
117
117
|
choice["message"] = { "reasoning_details" => answer[:reasoning_details] } if answer[:reasoning_details]
|
|
118
|
-
{ "choices" => [choice] }
|
|
118
|
+
{ "choices" => [ choice ] }
|
|
119
119
|
end
|
|
120
120
|
|
|
121
121
|
def tool_calls_for(answer)
|
|
122
|
-
calls = answer[:tool_calls] || Array(answer[:cmd]).map { { name: "bash", arguments: { "command" =>
|
|
122
|
+
calls = answer[:tool_calls] || Array(answer[:cmd]).map { { name: "bash", arguments: { "command" => it } } }
|
|
123
123
|
calls.to_h do |call|
|
|
124
124
|
id = call[:id] || "call_#{@llm_answer_ids = @llm_answer_ids.to_i + 1}"
|
|
125
|
-
[id, RubyLLM::ToolCall.new(id: id, name: call[:name], arguments: call[:arguments],
|
|
126
|
-
thought_signature: call[:thought_signature])]
|
|
125
|
+
[ id, RubyLLM::ToolCall.new(id: id, name: call[:name], arguments: call[:arguments],
|
|
126
|
+
thought_signature: call[:thought_signature]) ]
|
|
127
127
|
end
|
|
128
128
|
end
|
|
129
129
|
end
|
data/lib/miniswen/trajectory.rb
CHANGED
|
@@ -83,7 +83,7 @@ module Miniswen
|
|
|
83
83
|
end
|
|
84
84
|
|
|
85
85
|
def tool_calls_for(calls)
|
|
86
|
-
calls.map { { tool_call_id:
|
|
86
|
+
calls.map { { tool_call_id: it[:id], function_name: it[:name], arguments: it[:arguments] } }
|
|
87
87
|
end
|
|
88
88
|
|
|
89
89
|
def metrics_for(metrics)
|
data/lib/miniswen/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: lemans
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.0.
|
|
4
|
+
version: 1.0.0.rc.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Svyatoslav Kryukov
|
|
8
8
|
- Artur Petrov
|
|
9
|
+
- Vladimir Dementyev
|
|
9
10
|
bindir: exe
|
|
10
11
|
cert_chain: []
|
|
11
12
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
@@ -140,6 +141,7 @@ description: Lemans runs tasks against a coding agent in a sandbox.
|
|
|
140
141
|
email:
|
|
141
142
|
- me@skryukov.dev
|
|
142
143
|
- ardecvz@gmail.com
|
|
144
|
+
- dementiev.vm@gmail.com
|
|
143
145
|
executables:
|
|
144
146
|
- lemans
|
|
145
147
|
- lemans-remote
|
|
@@ -163,6 +165,17 @@ files:
|
|
|
163
165
|
- lib/lemans/cli/progress_reporter.rb
|
|
164
166
|
- lib/lemans/cli/report.rb
|
|
165
167
|
- lib/lemans/cli/report/aggregate.rb
|
|
168
|
+
- lib/lemans/cli/templates/bench/README.md
|
|
169
|
+
- lib/lemans/cli/templates/bench/bench.yml
|
|
170
|
+
- lib/lemans/cli/templates/bench/environment/Dockerfile
|
|
171
|
+
- lib/lemans/cli/templates/bench/tasks/example-task/environment.patch
|
|
172
|
+
- lib/lemans/cli/templates/bench/tasks/example-task/instruction.md
|
|
173
|
+
- lib/lemans/cli/templates/bench/tasks/example-task/solution.patch
|
|
174
|
+
- lib/lemans/cli/templates/bench/tasks/example-task/verification_test.rb
|
|
175
|
+
- lib/lemans/cli/templates/bench/tasks/hello-world/environment.patch
|
|
176
|
+
- lib/lemans/cli/templates/bench/tasks/hello-world/instruction.md
|
|
177
|
+
- lib/lemans/cli/templates/bench/tasks/hello-world/solution.patch
|
|
178
|
+
- lib/lemans/cli/templates/bench/tasks/hello-world/verification_test.rb
|
|
166
179
|
- lib/lemans/clobber.rb
|
|
167
180
|
- lib/lemans/config.rb
|
|
168
181
|
- lib/lemans/config/agent.rb
|
|
@@ -186,6 +199,7 @@ files:
|
|
|
186
199
|
- lib/lemans/runner.rb
|
|
187
200
|
- lib/lemans/runner/executor.rb
|
|
188
201
|
- lib/lemans/runner/task.rb
|
|
202
|
+
- lib/lemans/secrets_filter.rb
|
|
189
203
|
- lib/lemans/store.rb
|
|
190
204
|
- lib/lemans/stores/fs.rb
|
|
191
205
|
- lib/lemans/task_definition.rb
|