Module: Legion::Extensions::Llm::Bedrock::Runners::Discovery

Extended by:
Discovery
Includes:
Discovery::Pipeline
Included in:
Discovery
Defined in:
lib/legion/extensions/llm/bedrock/runners/discovery.rb

Overview

Bedrock discovery runner: ONLY the Bedrock-specific work. The generic reconcile / claim / activate / probe (cadence + reactive) / replace / weight-publication / health-display pipeline is mixed in from the shared Discovery::Pipeline. Weight is NOT computed here — the shared WeightReconciler recomputes it from live settings at publish.

The catalog is NOT OpenAI-shaped: it is the AWS control-plane ListFoundationModels call (SDK client, not HTTP), and readiness is the same non-inference control-plane call. fetch_raw_models / model_id_from / check_health are therefore overridden entirely. The secondary physical id is the derived region/credential id (dedup/diagnostics only — never identity: the instance identity is the operator's config name), and the offering-draft evidence is the Bedrock catalog knowledge.

Instance Method Summary collapse

Instance Method Details

#build_callable(instance_cfg:) ⇒ Object



90
91
92
# File 'lib/legion/extensions/llm/bedrock/runners/discovery.rb', line 90

def build_callable(instance_cfg:)
  Legion::Extensions::Llm::Bedrock::Helpers::Callable.new(instance_cfg: instance_cfg, logger: log)
end

#build_offering_draft(instance_cfg:, instance_key:, model_id:, model_data:) ⇒ Object

── Offering draft (evidence + metadata; NO weight) ───────────────



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/legion/extensions/llm/bedrock/runners/discovery.rb', line 104

def build_offering_draft(instance_cfg:, instance_key:, model_id:, model_data:)
  tier = instance_cfg[:tier] || :cloud
  input_mods = extract_modalities(summary: model_data, field: :input_modalities)
  output_mods = extract_modalities(summary: model_data, field: :output_modalities)
  streaming = streaming_supported?(summary: model_data)

  Legion::Extensions::Llm::Inventory::OfferingDraft.new(
    provider_native_key: model_id,
    model: model_id,
    tier: tier,
    operation_evidence: build_operation_evidence(
      is_embedding: output_mods.include?('embedding'), streaming_supported: streaming
    ),
    capability_evidence: build_capability_evidence(
      input_mods: input_mods, output_mods: output_mods,
      streaming_supported: streaming, model_id: model_id
    ),
    context_evidence: build_context_evidence(model_id: model_id),
    max_output_evidence: build_max_output_evidence,
    embedding_dimensions_evidence: build_embedding_dimensions_evidence,
    model_revision_evidence: build_model_revision_evidence,
    tokenizer_evidence: build_tokenizer_evidence,
    quota_domains: build_quota_domains(instance_cfg: instance_cfg, model_id: model_id),
    metadata: (model_id: model_id, instance_key: instance_key),
    publication_source: :provider_catalog
  )
end

#check_health(instance_cfg:) ⇒ Object

Readiness is the same non-inference control-plane call as the catalog (ListFoundationModels) — Bedrock has no HTTP /health.



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/legion/extensions/llm/bedrock/runners/discovery.rb', line 70

def check_health(instance_cfg:)
  client = build_bedrock_client(instance_cfg: instance_cfg)
  client.list_foundation_models
  Legion::Extensions::Llm::Inventory::ReadinessResult.new(
    ready: true,
    reason: 'Bedrock ListFoundationModels succeeded',
    metadata: {
      region: Legion::Extensions::Llm::Bedrock::InstanceIdentity.resolve_region(instance_cfg: instance_cfg)
    }
  )
rescue NameError, NoMethodError, ArgumentError
  # Programming errors must fail loud — a swallowed one would leave
  # the instance stuck in :initializing with no actionable signal.
  raise
rescue Aws::Bedrock::Errors::ServiceError => e
  readiness_failure(operation: 'ListFoundationModels', error: e)
rescue StandardError => e
  readiness_failure(operation: 'health check', error: e)
end

#derive_physical_id(instance_cfg:) ⇒ Object

── Secondary physical id (dedup/diagnostics only) ──────────────── The derived region/credential id — never identity: the instance identity is the operator's config name. A credential-less config derives NO physical id (nil) instead of a provider-family fallback.



99
100
101
# File 'lib/legion/extensions/llm/bedrock/runners/discovery.rb', line 99

def derive_physical_id(instance_cfg:)
  Legion::Extensions::Llm::Bedrock::InstanceIdentity.derive_physical_id(instance_cfg: instance_cfg)
end

#fetch_raw_models(instance_cfg:) ⇒ Object

── Catalog (AWS control plane, not HTTP) ─────────────────────────



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/legion/extensions/llm/bedrock/runners/discovery.rb', line 37

def fetch_raw_models(instance_cfg:)
  client = build_bedrock_client(instance_cfg: instance_cfg)
  response = client.list_foundation_models
  response.respond_to?(:model_summaries) ? Array(response.model_summaries) : []
rescue NameError, NoMethodError, ArgumentError
  # Programming errors must fail loud — swallowing them here would
  # publish zero offerings for every instance (invisible).
  raise
rescue StandardError => e
  # B8: a failed control-plane observation is NOT an empty
  # catalog — CatalogFetchFailure means "no observation"; the
  # pipeline keeps the last published snapshot and the next tick
  # retries. A genuine empty catalog arrives as [] and still
  # publishes.
  handle_exception(e, level: :warn, handled: false,
                      operation: 'bedrock.runner.discovery.fetch_raw_models')
  raise CatalogFetchFailure, "Bedrock ListFoundationModels failed (#{e.class.name})", cause: e
end

#model_id_from(model_data) ⇒ Object

ListFoundationModels summaries carry the model id on :model_id (SDK Struct shape or Hash).



58
59
60
61
62
63
64
65
66
# File 'lib/legion/extensions/llm/bedrock/runners/discovery.rb', line 58

def model_id_from(model_data)
  if model_data.respond_to?(:model_id)
    model_data.model_id.to_s
  elsif model_data.is_a?(Hash)
    (model_data[:model_id] || model_data['model_id']).to_s
  else
    ''
  end
end