lemans 0.2.1 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d451c9e558e461c51e7be30bdc17d9921a0ae8f028d82946dd5c0538620c5c31
4
- data.tar.gz: 3ff346d1263965339b9e51b51eaefade1fdd581048cc6b21c876836503cef3c8
3
+ metadata.gz: 1cf8e2ef8780e6577e9810b782c4fd1fe37fbe5691589c3ef665c09068ef4121
4
+ data.tar.gz: c697394a89a3056df20a174e55f83ad2ab81038cff1662a2bb91da784184c9d6
5
5
  SHA512:
6
- metadata.gz: e8d4b6027bcb1734cdfb4ca6c4f9797577014dc138189bbafe99fd8476cd07ecec52dbe96c5ad6107f44776b500d92a687d790d202699199ecb90b130522ecf8
7
- data.tar.gz: e0a3ab512fad47cc54b2057d06af7ddd7c2cc27d3b6d7c81ac3284c49ba4109900171f871907f163eb89180d0b82312a4a9039710c13ca24a084a3efc9b6041f
6
+ metadata.gz: 223472ec514232b4ec45a5f735d5786a7932ccd929064cc2c92bc5ebe22a70470836a6054694598a2c761c8eeac21fc7d8dc608a8506d309f2f1bfa7ad0d53eb
7
+ data.tar.gz: 3d05d9d1a0c1cd3432cf87c76f2a0afa6ec4b05298be9d6dbc8519268fb7805c6535246550c394a764de56c674ef22dba0a6c103cec807614b43d3548684ca77
data/exe/lemans-remote CHANGED
@@ -13,8 +13,9 @@
13
13
  # exe/lemans-remote provision
14
14
  #
15
15
  # Fire-and-forget a bench run on remote Daytona sandboxes — one sandbox
16
- # per task (--run-in-band for a single sandbox); results are archived to
17
- # the lemans-remote-runs volume. Add --sync to wait for a single sandbox
16
+ # per task (--run-in-band for a single sandbox, --attempts N to repeat
17
+ # each task in N sandboxes); results are archived to the
18
+ # lemans-remote-runs volume. Add --sync to wait for a single sandbox
18
19
  # and download into ./runs directly instead:
19
20
  #
20
21
  # exe/lemans-remote run --bench ../ai-evals --task hello-world
@@ -22,7 +23,7 @@
22
23
  #
23
24
  # Then watch, fetch, and clean up:
24
25
  #
25
- # exe/lemans-remote status [--history]
26
+ # exe/lemans-remote status [--history] [--running | --complete]
26
27
  # exe/lemans-remote pull-runs [RUN_ID ...] [--all]
27
28
  # exe/lemans-remote clobber RUN_ID ... | --all
28
29
  #
@@ -722,6 +723,7 @@ module LemansRemote
722
723
  option :sync, type: :boolean, default: false, desc: "Wait for the run and download the results directly"
723
724
  option :run_in_band, type: :boolean, default: false, aliases: %w[--runInBand],
724
725
  desc: "Async mode: run all tasks in one sandbox instead of one sandbox per task"
726
+ option :attempts, type: :numeric, default: 1, desc: "Async mode: repeat each task batch N times, one sandbox per attempt"
725
727
  option :keep, type: :boolean, default: false, desc: "Sync mode: leave the sandbox around for debugging"
726
728
  option :runs_dir, default: "runs", desc: "Sync mode: local directory to sync the results into"
727
729
  option :env, repeatable: true, desc: "Forward an extra host ENV variable by name"
@@ -736,19 +738,26 @@ module LemansRemote
736
738
  raise Thor::Error, "lemans-remote: snapshot #{provisioner.name} not found — run `lemans-remote provision` first"
737
739
  end
738
740
 
741
+ attempts = options[:attempts].to_i
742
+ raise Thor::Error, "lemans-remote: --attempts must be at least 1" if attempts < 1
743
+ raise Thor::Error, "lemans-remote: --attempts needs async mode — drop --sync" if options[:sync] && attempts > 1
744
+
739
745
  models = options[:model] || []
740
746
  batches = plan_batches(bench, tasks)
747
+ jobs = batches.flat_map { |batch| (1..attempts).map { [batch, attempts > 1 ? _1 : nil] } }
741
748
  Vault.ensure unless options[:sync]
742
749
 
743
- if batches.size == 1
744
- exit_code = launch_batch(bench, batches.first, models, provisioner)
750
+ if jobs.size == 1
751
+ batch, attempt = jobs.first
752
+ exit_code = launch_batch(bench, batch, models, provisioner, attempt:)
745
753
  say_status :detached, "`lemans-remote status` to watch, `lemans-remote pull-runs` to fetch results" unless options[:sync]
746
754
  exit exit_code unless exit_code.zero?
747
755
  return
748
756
  end
749
757
 
750
- say_status :fanout, "#{batches.size} sandboxes, one per task"
751
- failures = launch_batches(bench, batches, models, provisioner)
758
+ fanout = attempts > 1 ? "#{batches.size} task batch(es) × #{attempts} attempts" : "one per task"
759
+ say_status :fanout, "#{jobs.size} sandboxes, #{fanout}"
760
+ failures = launch_batches(bench, jobs, models, provisioner)
752
761
  say_status :detached, "`lemans-remote status` to watch, `lemans-remote pull-runs` to fetch results"
753
762
  raise Thor::Error, "lemans-remote: failed to launch: #{failures.join("; ")}" if failures.any?
754
763
  rescue Lemans::ConfigError, RuntimeError => e
@@ -757,6 +766,8 @@ module LemansRemote
757
766
 
758
767
  desc "status", "List lemans-remote runs (--history adds completed runs whose sandboxes are gone)"
759
768
  option :history, type: :boolean, default: false, desc: "Also read the vault manifests (spins a short-lived helper sandbox)"
769
+ option :running, type: :boolean, default: false, desc: "Only show runs still in flight"
770
+ option :complete, type: :boolean, default: false, desc: "Only show finished runs (success, failed, or stale)"
760
771
  def status
761
772
  rows = Fleet.rows.map { [_1.run_id, _1.status, _1.started_at || "?", _1.state, _1.sandbox.id] }
762
773
  if options[:history]
@@ -768,8 +779,15 @@ module LemansRemote
768
779
  end
769
780
  end
770
781
 
782
+ filtered = options[:running] ^ options[:complete]
783
+ rows.select! { (_1[1] == "running") == options[:running] } if filtered
784
+
771
785
  if rows.empty?
772
- say "no lemans-remote runs#{options[:history] ? "" : " — try --history for completed ones"}"
786
+ if filtered
787
+ say "no #{options[:running] ? "running" : "complete"} lemans-remote runs"
788
+ else
789
+ say "no lemans-remote runs#{options[:history] ? "" : " — try --history for completed ones"}"
790
+ end
773
791
  return
774
792
  end
775
793
 
@@ -892,11 +910,11 @@ module LemansRemote
892
910
  expanded.map { [_1] }
893
911
  end
894
912
 
895
- def launch_batch(bench, tasks, models, provisioner)
913
+ def launch_batch(bench, tasks, models, provisioner, attempt: nil)
896
914
  Runner.new(
897
915
  bench: bench,
898
916
  snapshot: provisioner.name,
899
- run_id: build_run_id(bench, tasks, models),
917
+ run_id: build_run_id(bench, tasks, models, attempt),
900
918
  tasks: tasks,
901
919
  models: models,
902
920
  extra_args: options[:args].strip,
@@ -909,24 +927,26 @@ module LemansRemote
909
927
  ).call
910
928
  end
911
929
 
912
- def launch_batches(bench, batches, models, provisioner)
930
+ def launch_batches(bench, jobs, models, provisioner)
913
931
  queue = Queue.new
914
- batches.each { queue << _1 }
932
+ jobs.each { queue << _1 }
915
933
  failures = Queue.new
916
934
 
917
- threads = [FANOUT_THREADS, batches.size].min.times.map do
935
+ threads = [FANOUT_THREADS, jobs.size].min.times.map do
918
936
  Thread.new do
919
937
  loop do
920
- batch =
938
+ batch, attempt =
921
939
  begin
922
940
  queue.pop(true)
923
941
  rescue ThreadError
924
942
  break
925
943
  end
926
944
  begin
927
- launch_batch(bench, batch, models, provisioner)
945
+ launch_batch(bench, batch, models, provisioner, attempt:)
928
946
  rescue StandardError => e
929
- failures << "#{batch.join(",")} (#{e.message})"
947
+ label = batch.empty? ? "all" : batch.join(",")
948
+ label += "/a#{attempt}" if attempt
949
+ failures << "#{label} (#{e.message})"
930
950
  end
931
951
  end
932
952
  end
@@ -936,7 +956,7 @@ module LemansRemote
936
956
  Array.new(failures.size) { failures.pop }
937
957
  end
938
958
 
939
- def build_run_id(bench, tasks, models)
959
+ def build_run_id(bench, tasks, models, attempt = nil)
940
960
  parts = [bench.root.basename.to_s]
941
961
  parts << (tasks.size == 1 ? tasks.first : "#{tasks.size}tasks") if tasks.any?
942
962
  if models.any?
@@ -944,6 +964,7 @@ module LemansRemote
944
964
  short += "+#{models.size - 1}" if models.size > 1
945
965
  parts << short
946
966
  end
967
+ parts << "a#{attempt}" if attempt
947
968
  parts << (ENV["LEMANS_REMOTE_USER"] || ENV["USER"] || "anon")
948
969
  parts << Time.now.utc.strftime("%Y%m%dT%H%M%S")
949
970
  parts << SecureRandom.alphanumeric(4).downcase
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Lemans
4
- VERSION = "0.2.1"
4
+ VERSION = "0.2.2"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lemans
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Svyatoslav Kryukov
@@ -114,6 +114,7 @@ email:
114
114
  - ardecvz@gmail.com
115
115
  executables:
116
116
  - lemans
117
+ - lemans-remote
117
118
  extensions: []
118
119
  extra_rdoc_files: []
119
120
  files: