Module: AgentHarness::ModelCompatibility

Defined in:
lib/agent_harness/model_compatibility.rb

Overview

Structured runner/model compatibility contract.

ModelCompatibility is the single source of truth for whether a given runner (provider) can execute a particular model under specific runtime constraints such as authentication mode or installed CLI version. Downstream orchestrators (for example Paid’s RDR-040 tier-to-model mapping) consume this contract before validating tier models, selecting runners, and starting agent runs — instead of inferring compatibility from scattered facts like CLI version pins, smoke-test overrides, or observed runtime errors.

Examples:

Query Codex compatibility for a CLI-gated model

AgentHarness.model_compatibility(
  runner: :codex,
  model_id: "gpt-5.5",
  auth_mode: :subscription,
  cli_version: "0.116.0"
)
# => #<AgentHarness::ModelCompatibility::Result supported=true ...>

Defined Under Namespace

Classes: Result

Constant Summary collapse

UNKNOWN_REASON =

Sentinel for “the runner declares no opinion about this model.”

:unknown
UNKNOWN_MODEL_REASON =

Issued when a runner does not advertise the requested model at all.

:unknown_model
UNKNOWN_CLI_VERSION_REASON =

Issued when the runner needs a comparable CLI version to answer definitively for a CLI-gated model but the caller did not supply one (or it could not be parsed). Pairs with :minimum_cli_version on the result. Distinct from :unknown_model — the runner does know the model; it just cannot confirm the installed CLI is new enough.

:cli_version_unknown
UNSUPPORTED_CLI_VERSION_REASON =

Issued when the runner supports the model but the installed CLI is too old. Pairs with :minimum_cli_version on the result.

:cli_version_too_old
UNSUPPORTED_AUTH_MODE_REASON =

Issued when the runner supports the model but the requested auth mode is not part of the runner’s contract for it.

:auth_mode_not_supported
SUPPORTED_REASON =

Default supported reason.

:supported
SOURCES =

Sources for a compatibility decision. Static contracts are baked into the provider; live probes hit the provider CLI/API; entitlement checks gate on subscription state. Downstream orchestrators can use this to decide whether to cache the answer.

%i[static_contract live_provider_probe entitlement_check unknown].freeze

Class Method Summary collapse

Class Method Details

.build_result(runner:, model_id:, **attributes) ⇒ Result

Build a Result with sensible defaults from a partial Hash.

Provider implementations call this helper to return a normalized Result without having to instantiate Struct fields by hand.

Parameters:

  • runner (Symbol)

    canonical provider/runner name

  • model_id (String, Symbol, nil)

    requested model id

  • attributes (Hash)

    additional Result attributes

Returns:



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/agent_harness/model_compatibility.rb', line 91

def build_result(runner:, model_id:, **attributes)
  normalized_model_id = model_id.is_a?(Symbol) ? model_id.to_s : model_id
  source = attributes.fetch(:source, :static_contract)
  supported = attributes[:supported]

  if supported == false && attributes[:reason].nil?
    raise ArgumentError,
      "AgentHarness::ModelCompatibility.build_result requires an explicit " \
      "`reason:` when `supported: false`. Pass a specific reason " \
      "(e.g. :cli_version_too_old, :auth_mode_not_supported) so " \
      "callers can distinguish unsupported from :unknown."
  end

  reason = attributes[:reason] || default_reason_for(supported)

  Result.new(
    runner: runner.to_sym,
    model_id: normalized_model_id,
    auth_mode: attributes[:auth_mode],
    cli_version: attributes[:cli_version],
    supported: supported,
    reason: reason,
    minimum_cli_version: attributes[:minimum_cli_version],
    cli_version_requirement: attributes[:cli_version_requirement],
    fallback_model_id: attributes[:fallback_model_id],
    source: source,
    details: attributes[:details]
  )
end

.unknown_result(runner:, model_id:, fallback_model_id: nil, **attributes) ⇒ Object

Build an explicit “unknown” Result. Use when the runner has no static contract for the requested model and cannot probe.



123
124
125
126
127
128
129
130
131
132
133
# File 'lib/agent_harness/model_compatibility.rb', line 123

def unknown_result(runner:, model_id:, fallback_model_id: nil, **attributes)
  build_result(
    runner: runner,
    model_id: model_id,
    supported: nil,
    reason: attributes.delete(:reason) || UNKNOWN_REASON,
    fallback_model_id: fallback_model_id,
    source: attributes.delete(:source) || :unknown,
    **attributes
  )
end