miniswen 1.2.0 → 1.3.1

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: de70dca3df1d5d69b884c838142ecf6143714e4160df12cd70ffd9d82d9cd823
4
- data.tar.gz: 9fc776f43acb75cd49b0b02a45dbaf2017927c2a5a9d0ac53589925b5be6cb99
3
+ metadata.gz: e4c9e3b53432be806eb3a0822777bafd74b6656e5c3577e2b7a41f70f24f6a97
4
+ data.tar.gz: a533f95356c1b8ba40606a25cc79f6e6da885fe42251daf436dcad62df6a273e
5
5
  SHA512:
6
- metadata.gz: b65975d0c54ef1588a896917dc7ee86b1c87c7a6c750d0354e6d1d8681743e20c2561890ebeefbce3cae2d96981ac5b41c26a6411b2d350653bce026ca9e730c
7
- data.tar.gz: c067f93043fd5f056a243200b08e5d92bd3c4d25356bc961ae8a377e2dc86ef91600ce9d468747f5b18daa746be2f50e87122f5ad9ea4de6827b0fb1e1727b84
6
+ metadata.gz: bf213b85fd14ef0ec93b94409361f490b82769f70b6d6fbef8917688a9510c29366f7825c0ecdf951824a42ed19a33a23530679c23108f852996486ffd5d92db
7
+ data.tar.gz: a9328e4313ce9abbe5843368428f4e85752cc9690c00e6bfe8c68321e8c820ce1000996472c76aded6eef0fa988815c9a2a7348bc12bc953ea356f980184bd71
data/README.md CHANGED
@@ -88,6 +88,7 @@ agent:
88
88
  timeout: 30m
89
89
  step_limit: 100
90
90
  cost_limit: 5.0
91
+ # max_output_tokens: 32768 # [optional] output cap per model call, for hosts that reserve the model's full max output out of the context window (default: the provider's)
91
92
  environment:
92
93
  network: # the sandbox network while the agent works: just enough to reach the model
93
94
  mode: allowlist
@@ -142,7 +143,7 @@ A minimal task example—checking whether an agent can write "Hello, world" into
142
143
  +Hello, world
143
144
  ```
144
145
 
145
- - `verification_test.rb`: a Ruby test that grades the solution (pass → 1, fail → 0; for partial credit, write a float in 0.0..1.0 to `$LOGS/reward.txt` instead). A check worth recording but not grading goes into `allow_failure { ... }` (`include LemansReport::Assertions`): a failed assertion inside lands in `checks.json` as `fail (allowed)` with its message and leaves the reward alone, while errors and skips stay hard failures. We use Minitest:
146
+ - `verification_test.rb`: a Ruby test that grades the solution (pass → 1, fail → 0; for partial credit, write a float in 0.0..1.0 to `$LOGS/reward.txt` instead). A check worth recording but not grading goes into `allow_failure { ... }` (`include LemansReport::Assertions`): a failed assertion inside lands in `checks.json` as `fail (allowed)` with its message and leaves the reward alone, while errors and skips stay hard failures (a test may call `allow_failure` once). For fractional credit next to the reward, say what passing the required checks alone is worth (`LemansReport.base_credit = 0.7`) and weight the allowed failures (`allow_failure(points: 2) { ... }`, 1 by default): the trial's `credit` is the base credit plus the remainder scaled by the share of extra points passed, rounded to two digits — 0 whenever the suite fails, and simply the reward when no `base_credit` is set. We use Minitest:
146
147
 
147
148
  ```ruby
148
149
  require "minitest/autorun"
@@ -218,11 +219,11 @@ ar-archive-book-access miniswen-installed gpt-5.6-luna 1 completed 0.0
218
219
  6 trials: 6 scored, 0 invalid, 6 solved (100%) · $0.0801 · pass@2 3/3 tasks (100%)
219
220
  ```
220
221
 
221
- `lemans run` runs all the tasks for the model defined in `bench.yml` and prints the report at the end. You can override the model(s) to use (`--model`), the number of attempts (`--attempts`), or select specific tasks by name (`--task=ac-throttle-search`, may be repeated).
222
+ `lemans run` runs all the tasks for the model defined in `bench.yml` and prints the report at the end. You can override the model(s) to use (`--model`), the agent's output cap per model call (`--max-output-tokens`), the number of attempts (`--attempts`), or select specific tasks by name (`--task=ac-throttle-search`, may be repeated).
222
223
 
223
224
  Each trial writes a flat `runs/<model>/<task>__<id>/` directory:
224
225
 
225
- - `result.json`: reward, outcome (completed, error, etc.), usage, timings, tags, digests
226
+ - `result.json`: reward, credit, outcome (completed, error, etc.), usage, timings, tags, digests
226
227
  - `trajectory.json`: [ATIF](https://www.harborframework.com/docs/agents/trajectory-format) trajectory of the agent's session
227
228
  - `agent.patch`: the agent's work as one diff against the sealed baseline
228
229
  - `verifier.log`, `checks.json`, etc.: additional logs captured during the verification phase.
@@ -253,8 +254,8 @@ gpt-5.6-luna ar-archive-book-access 2/2 2m 23s $0.0132 12.5 156905
253
254
  | --- | --- |
254
255
  | `lemans init` | Scaffold a new bench directory: an annotated `bench.yml` and two example tasks |
255
256
  | `lemans tasks` | List the tasks in a bench (`--tag` to filter) |
256
- | `lemans run` | Run tasks and grade them (`--task`, `--tag`, `--agent`, `--model`, `-k`, `-c`, `--resume`) |
257
- | `lemans report` | Summarize `runs/` as a table or CSV (`--tag`, `-A [task-agent-model]` to aggregate, `-S <column>` to sort); repeated attempts add pass@k per model × task |
257
+ | `lemans run` | Run tasks and grade them (`--task`, `--tag`, `--agent`, `--model`, `--max-output-tokens`, `-k`, `-c`, `--resume`) |
258
+ | `lemans report` | Summarize `runs/` as a table or CSV (`--task`, `--tag`, `--metadata key:value` to filter, `-A [task-agent-model]` to aggregate, `-S <column>` to sort); repeated attempts add pass@k per model × task, fractional grading a `credit` column |
258
259
  | `lemans clobber` | Delete run results (`--task`, `--ttl 10m\|2h\|1d`, `--invalid`, `-f` to skip the confirmation) |
259
260
 
260
261
  ## miniswen
@@ -14,7 +14,7 @@ module Miniswen
14
14
 
15
15
  # Both finish_reason dialects accepted raw: OpenAI-shaped providers say
16
16
  # "length"/"tool_calls", Anthropic says "max_tokens"/"tool_use".
17
- TRUNCATION_FINISH_REASONS = %w[length max_tokens].freeze
17
+ TRUNCATION_FINISH_REASONS = %w[length max_tokens model_context_window_exceeded].freeze
18
18
  CLAIMED_TOOL_FINISH_REASONS = %w[tool_calls tool_use].freeze
19
19
  # A safety stop, which arrives looking exactly like a model that forgot
20
20
  # to call the tool: no content, no tool call, and — since the provider
@@ -224,19 +224,20 @@ module Miniswen
224
224
  end
225
225
 
226
226
  CostSource = Data.define(:name, :model, :priced_as, :registry) do
227
- def to_h = { name: name, model: model, priced_as: priced_as, registry: registry }.compact
227
+ def to_h = { name:, model:, priced_as:, registry: }.compact
228
228
  end
229
229
 
230
230
  attr_reader :messages, :environment
231
231
 
232
- private attr_reader :max_steps, :max_time, :max_cost, :exec_timeout,
232
+ private attr_reader :max_steps, :max_time, :max_cost, :exec_timeout, :max_output_tokens,
233
233
  :clock, :reporter
234
234
 
235
235
  # `model` is a litellm-style name ("openrouter/z-ai/glm-5.2"), optionally
236
236
  # suffixed with a reasoning effort ("openrouter/openai/gpt-5.6-luna#xhigh").
237
237
  # Limits of 0 or nil are disabled.
238
238
  def initialize(model:, environment:, max_steps: 0, max_time: 0, max_cost: nil,
239
- exec_timeout: 30, clock: -> { Process.clock_gettime(Process::CLOCK_MONOTONIC) },
239
+ exec_timeout: 30, max_output_tokens: 0,
240
+ clock: -> { Process.clock_gettime(Process::CLOCK_MONOTONIC) },
240
241
  reporter: nil)
241
242
  name, @effort = model.split("#", 2)
242
243
  @provider, @id = name.split("/", 2)
@@ -254,6 +255,7 @@ module Miniswen
254
255
  @max_time = max_time.to_f
255
256
  @max_cost = max_cost
256
257
  @exec_timeout = exec_timeout
258
+ @max_output_tokens = max_output_tokens.to_i
257
259
 
258
260
  @clock = clock
259
261
  @reporter = reporter
@@ -503,7 +505,7 @@ module Miniswen
503
505
  tools: { bash: @bash_tool },
504
506
  temperature: nil,
505
507
  model: model_info,
506
- params: routing_params,
508
+ params: routing_params.merge(output_cap_params(model_info)),
507
509
  thinking: (RubyLLM::Thinking::Config.new(effort: @effort) if @effort)
508
510
  )
509
511
  payload(response)
@@ -543,6 +545,22 @@ module Miniswen
543
545
 
544
546
  def provider_order = ENV["LEMANS_PROVIDER_ORDER"] || ENV["OPENROUTER_PROVIDER_ORDER"]
545
547
 
548
+ # OpenAI itself retired `max_tokens` for its reasoning models; the
549
+ # OpenAI-compatible providers and Anthropic still read it.
550
+ def output_cap_params(model_info)
551
+ return {} if max_output_tokens.zero?
552
+
553
+ cap = [ info&.max_tokens, max_output_tokens ].compact.min
554
+ provider_class = RubyLLM::Provider.providers[model_info.provider.to_sym]
555
+ if [ RubyLLM::Providers::OpenAI, RubyLLM::Providers::Azure ].include?(provider_class)
556
+ { max_completion_tokens: cap }
557
+ elsif provider_class <= RubyLLM::Providers::OpenAI || provider_class <= RubyLLM::Providers::Anthropic
558
+ { max_tokens: cap }
559
+ else
560
+ {}
561
+ end
562
+ end
563
+
546
564
  def cost_source
547
565
  if local?
548
566
  return CostSource.new(name: :local_provider, model: @model,
data/lib/miniswen/cli.rb CHANGED
@@ -123,6 +123,10 @@ module Miniswen
123
123
  options[:exec_timeout] = v
124
124
  end
125
125
 
126
+ opts.on("--max-output-tokens=TOKENS", Integer, "Output cap per model call (default: the provider's)") do |v|
127
+ options[:max_output_tokens] = v
128
+ end
129
+
126
130
  opts.on("-q", "--quiet", "Disable progress output") do
127
131
  @quiet = true
128
132
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Miniswen
4
- VERSION = "1.2.0"
4
+ VERSION = "1.3.1"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: miniswen
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Svyatoslav Kryukov