Module: Space::Architect::Harness
- Defined in:
- lib/space_architect/harness.rb
Defined Under Namespace
Classes: ClaudeCodeHarness, OpenCodeHarness, PiHarness
Constant Summary collapse
- CLAUDE_DEFAULT_MODEL =
"claude-sonnet-5"- DEFAULT_MODELS =
Per-harness sensible default model, used when neither an explicit --model nor a space.yaml project.model is given.
{ "claude-code" => CLAUDE_DEFAULT_MODEL, "pi" => "qwen3-27b-optiq", "opencode" => "fireworks-ai/accounts/fireworks/models/glm-5p2" }.freeze
- THINKING_LEVELS =
The normalized internal thinking vocabulary — pi's fullest set. Every alias (--effort/--thinking/--reasoning) is normalized to a member of this array; each harness then translates + clamps down to its own flag's vocabulary.
%w[off minimal low medium high xhigh max].freeze
Class Method Summary collapse
- .default_model_for(harness_name) ⇒ Object
-
.for(name, model:, max_turns:, bin: nil, config_dir: nil, effort: nil, force: false, err: $stderr) ⇒ Object
Factory keyed by harness name.
-
.parse_model_suffix(model) ⇒ Object
Split a "model:level" id into [model, level] (level nil, model unchanged if no suffix).
-
.translate_thinking(harness, level, force: false) ⇒ Object
Per-harness translate + clamp: input a normalized level (or nil) and whether the caller forced it (skips clamping — the literal is passed through unmodified).
- .validate_thinking_level!(level) ⇒ Object
Class Method Details
.default_model_for(harness_name) ⇒ Object
23 24 25 |
# File 'lib/space_architect/harness.rb', line 23 def self.default_model_for(harness_name) DEFAULT_MODELS[harness_name.to_s] end |
.for(name, model:, max_turns:, bin: nil, config_dir: nil, effort: nil, force: false, err: $stderr) ⇒ Object
Factory keyed by harness name. Translates + clamps the normalized effort
level to the harness's own vocabulary, printing one inform line to err
(default $stderr; thread a null writer to suppress) when it clamps/strips.
With force: true, the literal effort value is passed through unmodified.
For opencode: config_dir is required (build/
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/space_architect/harness.rb', line 65 def self.for(name, model:, max_turns:, bin: nil, config_dir: nil, effort: nil, force: false, err: $stderr) translated, inform = translate_thinking(name, effort, force: force) err.puts(inform) if inform case name.to_s when "claude-code" ClaudeCodeHarness.new(model: model, max_turns: max_turns, bin: bin, effort: translated) when "opencode" raise Space::Core::Error, "config_dir is required for opencode harness" unless config_dir OpenCodeHarness.new(model: model, max_turns: max_turns, bin: bin, config_dir: config_dir, effort: translated) when "pi" raise Space::Core::Error, "config_dir is required for pi harness" unless config_dir PiHarness.new(model: model, max_turns: max_turns, bin: bin, config_dir: config_dir, effort: translated) else raise Space::Core::Error, "Unknown harness '#{name}' — valid values: claude-code, opencode, pi" end end |
.parse_model_suffix(model) ⇒ Object
Split a "model:level" id into [model, level] (level nil, model unchanged if no suffix). Only a trailing segment that is a member of THINKING_LEVELS is treated as a suffix — a model id containing a literal colon for another reason is left alone.
41 42 43 44 45 46 |
# File 'lib/space_architect/harness.rb', line 41 def self.parse_model_suffix(model) return [model, nil] unless model base, _, suffix = model.rpartition(":") return [model, nil] if base.empty? || !THINKING_LEVELS.include?(suffix) [base, suffix] end |
.translate_thinking(harness, level, force: false) ⇒ Object
Per-harness translate + clamp: input a normalized level (or nil) and whether the caller forced it (skips clamping — the literal is passed through unmodified). Returns [translated_level_or_nil, inform_line_or_nil].
51 52 53 54 55 56 57 58 |
# File 'lib/space_architect/harness.rb', line 51 def self.translate_thinking(harness, level, force: false) case harness.to_s when "claude-code" then ClaudeCodeHarness.translate_thinking(level, force: force) when "opencode" then OpenCodeHarness.translate_thinking(level, force: force) when "pi" then PiHarness.translate_thinking(level, force: force) else nil end end |
.validate_thinking_level!(level) ⇒ Object
32 33 34 35 36 |
# File 'lib/space_architect/harness.rb', line 32 def self.validate_thinking_level!(level) return if level.nil? || THINKING_LEVELS.include?(level) raise Space::Core::Error, "unknown thinking level '#{level}' — valid: #{THINKING_LEVELS.join(', ')}" end |