lex-llm-bedrock 0.3.6 → 0.3.8
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 +4 -4
- data/CHANGELOG.md +19 -0
- data/lib/legion/extensions/llm/bedrock/actors/fleet_worker.rb +14 -3
- data/lib/legion/extensions/llm/bedrock/provider.rb +100 -14
- data/lib/legion/extensions/llm/bedrock/runners/fleet_worker.rb +13 -0
- data/lib/legion/extensions/llm/bedrock/version.rb +1 -1
- data/lib/legion/extensions/llm/bedrock.rb +44 -7
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5ef7a8a909bb86688882fc9ffca3c7fd96955d75cb01e5048efa954909599c49
|
|
4
|
+
data.tar.gz: 90d58f5f3e6f976b2332341e6f5624064a5b70f7ce5381d4df94b082d7398ab7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ab5e3feccaee75a608ba7032721bd899e74e9059bfee3704ebc45b1f1733a5341eb2e1f1f99be48bdc2b0eee4555aaf8985e1c84a2c673474dbc4ae018abf6b7
|
|
7
|
+
data.tar.gz: 61b3a978d40a10d91f725ffd3ebc7b937596fa60740fb9e3d168cbba6f19fc2a50f27af56a637612c4980b1e4408dcae61e2148fff6b819026ed35811fbdcf6c
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.8 - 2026-05-13
|
|
4
|
+
|
|
5
|
+
- Auto-prefix `us.` on `inference_profile_id` for Anthropic, Meta, Mistral, Cohere, and AI21 models at API call time.
|
|
6
|
+
- Filter empty content blocks from messages to satisfy Bedrock validation.
|
|
7
|
+
- Wire Bearer token into AWS SDK via `Aws::StaticTokenProvider` to eliminate IMDS timeout on startup.
|
|
8
|
+
- Add `source` and `credential_fingerprint` fields to all discovered instances.
|
|
9
|
+
- Inject default capabilities into all discovered instances.
|
|
10
|
+
- Add static `CONTEXT_WINDOWS` map; `infer_limits` reads from `model_detail` cache instead of live API.
|
|
11
|
+
- Override `fetch_model_detail` to return static context window data without a network call.
|
|
12
|
+
- Cache live results in `discover_offerings`.
|
|
13
|
+
- Add `unresolved_credential?` filter — instances with `vault://` or `env://` credential refs are skipped during registration.
|
|
14
|
+
- Inject `default_model` into all discovered instances.
|
|
15
|
+
|
|
16
|
+
## 0.3.7 - 2026-05-12
|
|
17
|
+
|
|
18
|
+
- Use `Legion::Logging::Helper` explicitly across Bedrock provider, actor, and fleet runner logging surfaces.
|
|
19
|
+
- Add non-sensitive debug logging for Bedrock tool configuration and fleet request routing.
|
|
20
|
+
- Report optional actor runtime load failures through `handle_exception` instead of direct warning output.
|
|
21
|
+
|
|
3
22
|
## 0.3.6 - 2026-05-08
|
|
4
23
|
|
|
5
24
|
- Accept keyword arguments in `list_models` to match the base provider contract called by `discover_offerings`.
|
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'legion/extensions/llm/bedrock'
|
|
4
|
+
|
|
3
5
|
begin
|
|
4
6
|
require 'legion/extensions/actors/subscription'
|
|
5
7
|
rescue LoadError => e
|
|
6
|
-
|
|
8
|
+
Legion::Extensions::Llm::Bedrock.handle_exception(
|
|
9
|
+
e,
|
|
10
|
+
level: :debug,
|
|
11
|
+
handled: true,
|
|
12
|
+
operation: 'bedrock.actor.fleet_worker.load_subscription'
|
|
13
|
+
)
|
|
7
14
|
end
|
|
8
15
|
|
|
9
16
|
unless defined?(Legion::Extensions::Actors::Subscription)
|
|
10
17
|
raise LoadError, 'LegionIO actor runtime is required for Bedrock fleet worker'
|
|
11
18
|
end
|
|
12
19
|
|
|
13
|
-
require 'legion/extensions/llm/bedrock'
|
|
14
20
|
require 'legion/extensions/llm/fleet/provider_responder'
|
|
15
21
|
|
|
16
22
|
module Legion
|
|
@@ -20,6 +26,8 @@ module Legion
|
|
|
20
26
|
module Actor
|
|
21
27
|
# Subscription actor for Bedrock fleet request consumption.
|
|
22
28
|
class FleetWorker < Legion::Extensions::Actors::Subscription
|
|
29
|
+
include Legion::Logging::Helper
|
|
30
|
+
|
|
23
31
|
def runner_class
|
|
24
32
|
'Legion::Extensions::Llm::Bedrock::Runners::FleetWorker'
|
|
25
33
|
end
|
|
@@ -33,7 +41,10 @@ module Legion
|
|
|
33
41
|
end
|
|
34
42
|
|
|
35
43
|
def enabled?
|
|
36
|
-
|
|
44
|
+
instances = Bedrock.discover_instances
|
|
45
|
+
enabled = Legion::Extensions::Llm::Fleet::ProviderResponder.enabled_for?(instances)
|
|
46
|
+
log.debug { "bedrock.actor.fleet_worker.enabled?: instances=#{instances.size} enabled=#{enabled}" }
|
|
47
|
+
enabled
|
|
37
48
|
end
|
|
38
49
|
end
|
|
39
50
|
end
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
require 'aws-sdk-bedrock'
|
|
4
4
|
require 'aws-sdk-bedrockruntime'
|
|
5
5
|
require 'legion/json'
|
|
6
|
-
require 'legion/logging'
|
|
6
|
+
require 'legion/logging/helper'
|
|
7
7
|
require 'legion/extensions/llm'
|
|
8
8
|
|
|
9
9
|
module Legion
|
|
@@ -26,6 +26,28 @@ module Legion
|
|
|
26
26
|
|
|
27
27
|
ALIASES = STATIC_MODELS.to_h { |entry| [entry.fetch(:alias), entry.fetch(:model)] }.freeze
|
|
28
28
|
|
|
29
|
+
CONTEXT_WINDOWS = {
|
|
30
|
+
'anthropic.claude-sonnet-4' => 200_000,
|
|
31
|
+
'anthropic.claude-haiku-4' => 200_000,
|
|
32
|
+
'anthropic.claude-opus-4' => 200_000,
|
|
33
|
+
'anthropic.claude-3-5-sonnet' => 200_000,
|
|
34
|
+
'anthropic.claude-3-5-haiku' => 200_000,
|
|
35
|
+
'anthropic.claude-3-haiku' => 200_000,
|
|
36
|
+
'anthropic.claude-3-opus' => 200_000,
|
|
37
|
+
'anthropic.claude-3-sonnet' => 200_000,
|
|
38
|
+
'meta.llama3' => 128_000,
|
|
39
|
+
'meta.llama3-1' => 128_000,
|
|
40
|
+
'meta.llama3-2' => 128_000,
|
|
41
|
+
'meta.llama3-3' => 128_000,
|
|
42
|
+
'mistral.mistral-large' => 128_000,
|
|
43
|
+
'mistral.mistral-small' => 128_000,
|
|
44
|
+
'amazon.titan-text-express' => 8_192,
|
|
45
|
+
'amazon.titan-text-premier' => 32_000,
|
|
46
|
+
'amazon.nova-pro' => 300_000,
|
|
47
|
+
'amazon.nova-lite' => 300_000,
|
|
48
|
+
'amazon.nova-micro' => 128_000
|
|
49
|
+
}.freeze
|
|
50
|
+
|
|
29
51
|
class << self
|
|
30
52
|
def slug = 'bedrock'
|
|
31
53
|
|
|
@@ -38,6 +60,7 @@ module Legion
|
|
|
38
60
|
bedrock_session_token
|
|
39
61
|
bedrock_profile
|
|
40
62
|
bedrock_stub_responses
|
|
63
|
+
bearer_token
|
|
41
64
|
]
|
|
42
65
|
end
|
|
43
66
|
|
|
@@ -51,6 +74,15 @@ module Legion
|
|
|
51
74
|
def resolve_model_id(model_id, config: nil) # rubocop:disable Lint/UnusedMethodArgument
|
|
52
75
|
ALIASES.fetch(model_id.to_s, model_id.to_s)
|
|
53
76
|
end
|
|
77
|
+
|
|
78
|
+
INFERENCE_PROFILE_PREFIXES = %w[anthropic. meta. mistral. cohere. ai21.].freeze
|
|
79
|
+
|
|
80
|
+
def inference_profile_id(model)
|
|
81
|
+
return model if model.start_with?('us.', 'eu.', 'ap.', 'arn:')
|
|
82
|
+
return model unless INFERENCE_PROFILE_PREFIXES.any? { |p| model.start_with?(p) }
|
|
83
|
+
|
|
84
|
+
"us.#{model}"
|
|
85
|
+
end
|
|
54
86
|
end
|
|
55
87
|
|
|
56
88
|
# Capability predicates inferred from Bedrock model IDs and API modalities.
|
|
@@ -86,15 +118,19 @@ module Legion
|
|
|
86
118
|
|
|
87
119
|
def discover_offerings(live: false, **filters)
|
|
88
120
|
unless live
|
|
121
|
+
return @cached_offerings if @cached_offerings&.any?
|
|
122
|
+
|
|
89
123
|
log.debug { 'bedrock.provider.discover_offerings: returning static catalog' }
|
|
90
124
|
return static_offerings(**filters)
|
|
91
125
|
end
|
|
92
126
|
|
|
93
127
|
log.info { "bedrock.provider.discover_offerings: listing foundation models (region=#{region})" }
|
|
94
128
|
response = bedrock_client.list_foundation_models(**filters)
|
|
95
|
-
Array(value(response, :model_summaries)).map
|
|
96
|
-
|
|
129
|
+
@cached_offerings = Array(value(response, :model_summaries)).map do |summary|
|
|
130
|
+
offering_from_summary(summary)
|
|
97
131
|
end
|
|
132
|
+
log.info { "bedrock.provider.discover_offerings: found #{@cached_offerings.size} models" }
|
|
133
|
+
@cached_offerings
|
|
98
134
|
end
|
|
99
135
|
|
|
100
136
|
def offering_for(model:, model_family: nil, instance_id: :default, **metadata)
|
|
@@ -164,6 +200,10 @@ module Legion
|
|
|
164
200
|
converse_request(messages, model:, temperature:, max_tokens:, tools:, tool_prefs:),
|
|
165
201
|
params
|
|
166
202
|
)
|
|
203
|
+
log.debug do
|
|
204
|
+
"bedrock.provider.chat: request prepared model=#{model_id(model)} tools=#{tools.size} " \
|
|
205
|
+
"tool_choice=#{tool_choice_label(tool_prefs)} param_keys=#{params.keys.map(&:to_s).sort.join(',')}"
|
|
206
|
+
end
|
|
167
207
|
parse_converse_response(runtime_client.converse(**request), model_id(model))
|
|
168
208
|
end
|
|
169
209
|
|
|
@@ -174,6 +214,10 @@ module Legion
|
|
|
174
214
|
converse_request(messages, model:, temperature:, max_tokens:, tools:, tool_prefs:),
|
|
175
215
|
params
|
|
176
216
|
)
|
|
217
|
+
log.debug do
|
|
218
|
+
"bedrock.provider.stream: request prepared model=#{model_id(model)} tools=#{tools.size} " \
|
|
219
|
+
"tool_choice=#{tool_choice_label(tool_prefs)} param_keys=#{params.keys.map(&:to_s).sort.join(',')}"
|
|
220
|
+
end
|
|
177
221
|
stream_converse(request, model_id(model), &)
|
|
178
222
|
end
|
|
179
223
|
|
|
@@ -186,7 +230,7 @@ module Legion
|
|
|
186
230
|
log.debug { "bedrock.provider.count_tokens: model=#{model_id(model)}" }
|
|
187
231
|
request = Utils.deep_merge(
|
|
188
232
|
{
|
|
189
|
-
model_id: model_id(model),
|
|
233
|
+
model_id: self.class.inference_profile_id(model_id(model)),
|
|
190
234
|
input: { converse: { messages: format_messages(messages), system: system_blocks(system) }.compact }
|
|
191
235
|
},
|
|
192
236
|
params
|
|
@@ -275,6 +319,7 @@ module Legion
|
|
|
275
319
|
|
|
276
320
|
def build_offering(model:, model_family:, usage_type:, instance_id: :default, alias_name: nil,
|
|
277
321
|
capabilities: nil, metadata: {})
|
|
322
|
+
limits = infer_limits(model)
|
|
278
323
|
Legion::Extensions::Llm::Routing::ModelOffering.new(
|
|
279
324
|
provider_family: :bedrock,
|
|
280
325
|
instance_id: instance_id,
|
|
@@ -283,10 +328,24 @@ module Legion
|
|
|
283
328
|
model: model,
|
|
284
329
|
usage_type: usage_type,
|
|
285
330
|
capabilities: capabilities || default_capabilities(model),
|
|
331
|
+
limits: limits,
|
|
286
332
|
metadata: metadata.merge(model_family: model_family, alias: alias_name).compact
|
|
287
333
|
)
|
|
288
334
|
end
|
|
289
335
|
|
|
336
|
+
def infer_limits(model)
|
|
337
|
+
detail = model_detail(model.to_s)
|
|
338
|
+
return detail if detail.is_a?(Hash) && detail[:context_window]
|
|
339
|
+
|
|
340
|
+
ctx = CONTEXT_WINDOWS.find { |prefix, _| model.to_s.start_with?(prefix) }&.last
|
|
341
|
+
ctx ? { context_window: ctx } : {}
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
def fetch_model_detail(model_name)
|
|
345
|
+
ctx = CONTEXT_WINDOWS.find { |prefix, _| model_name.start_with?(prefix) }&.last
|
|
346
|
+
ctx ? { context_window: ctx } : nil
|
|
347
|
+
end
|
|
348
|
+
|
|
290
349
|
def configured_transport(default)
|
|
291
350
|
config.respond_to?(:transport) ? config.transport : default
|
|
292
351
|
end
|
|
@@ -297,7 +356,7 @@ module Legion
|
|
|
297
356
|
|
|
298
357
|
def converse_request(messages, model:, temperature:, max_tokens:, tools:, tool_prefs:)
|
|
299
358
|
{
|
|
300
|
-
model_id: model_id(model),
|
|
359
|
+
model_id: self.class.inference_profile_id(model_id(model)),
|
|
301
360
|
messages: format_messages(messages.reject { |message| message.role == :system }),
|
|
302
361
|
system: format_system(messages),
|
|
303
362
|
inference_config: { temperature: temperature, max_tokens: max_tokens || model_max_tokens(model) }.compact,
|
|
@@ -306,11 +365,11 @@ module Legion
|
|
|
306
365
|
end
|
|
307
366
|
|
|
308
367
|
def format_messages(messages)
|
|
309
|
-
messages.
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
}
|
|
368
|
+
messages.filter_map do |message|
|
|
369
|
+
blocks = content_blocks(message.content)
|
|
370
|
+
next if blocks.empty?
|
|
371
|
+
|
|
372
|
+
{ role: bedrock_role(message.role), content: blocks }
|
|
314
373
|
end
|
|
315
374
|
end
|
|
316
375
|
|
|
@@ -331,7 +390,13 @@ module Legion
|
|
|
331
390
|
end
|
|
332
391
|
|
|
333
392
|
def content_blocks(content)
|
|
334
|
-
|
|
393
|
+
raw = raw_content(content)
|
|
394
|
+
return raw if raw
|
|
395
|
+
|
|
396
|
+
text = content_text(content)
|
|
397
|
+
return [] if text.strip.empty?
|
|
398
|
+
|
|
399
|
+
[{ text: text }]
|
|
335
400
|
end
|
|
336
401
|
|
|
337
402
|
def raw_content(content)
|
|
@@ -349,6 +414,10 @@ module Legion
|
|
|
349
414
|
def format_tool_config(tools, tool_prefs)
|
|
350
415
|
return nil if tools.empty?
|
|
351
416
|
|
|
417
|
+
log.debug do
|
|
418
|
+
"bedrock.provider.tools: formatting tools=#{tools.keys.map(&:to_s).sort.join(',')} " \
|
|
419
|
+
"tool_choice=#{tool_choice_label(tool_prefs)}"
|
|
420
|
+
end
|
|
352
421
|
{ tools: tools.values.map { |tool| tool_definition(tool) }, tool_choice: tool_choice(tool_prefs) }.compact
|
|
353
422
|
end
|
|
354
423
|
|
|
@@ -382,6 +451,12 @@ module Legion
|
|
|
382
451
|
end
|
|
383
452
|
end
|
|
384
453
|
|
|
454
|
+
def tool_choice_label(tool_prefs)
|
|
455
|
+
return 'none' unless tool_prefs
|
|
456
|
+
|
|
457
|
+
(tool_prefs[:choice] || tool_prefs['choice'] || 'unspecified').to_s
|
|
458
|
+
end
|
|
459
|
+
|
|
385
460
|
def parse_converse_response(response, fallback_model)
|
|
386
461
|
output = value(response, :output)
|
|
387
462
|
message = value(output, :message)
|
|
@@ -459,12 +534,23 @@ module Legion
|
|
|
459
534
|
end
|
|
460
535
|
|
|
461
536
|
def client_options
|
|
462
|
-
{
|
|
537
|
+
opts = {
|
|
463
538
|
region: region,
|
|
464
539
|
endpoint: config.bedrock_endpoint,
|
|
465
|
-
credentials: credentials,
|
|
466
540
|
stub_responses: config.bedrock_stub_responses
|
|
467
|
-
}
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
if bearer_token_configured?
|
|
544
|
+
opts[:token_provider] = Aws::StaticTokenProvider.new(config.bearer_token)
|
|
545
|
+
else
|
|
546
|
+
opts[:credentials] = credentials
|
|
547
|
+
end
|
|
548
|
+
|
|
549
|
+
opts.compact
|
|
550
|
+
end
|
|
551
|
+
|
|
552
|
+
def bearer_token_configured?
|
|
553
|
+
config.respond_to?(:bearer_token) && !config.bearer_token.to_s.empty?
|
|
468
554
|
end
|
|
469
555
|
|
|
470
556
|
def credentials
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require 'legion/extensions/llm/fleet/provider_responder'
|
|
4
4
|
require 'legion/extensions/llm/bedrock'
|
|
5
|
+
require 'legion/logging/helper'
|
|
5
6
|
|
|
6
7
|
module Legion
|
|
7
8
|
module Extensions
|
|
@@ -10,9 +11,15 @@ module Legion
|
|
|
10
11
|
module Runners
|
|
11
12
|
# Runner entrypoint for Bedrock fleet request execution.
|
|
12
13
|
module FleetWorker
|
|
14
|
+
extend Legion::Logging::Helper
|
|
15
|
+
|
|
13
16
|
module_function
|
|
14
17
|
|
|
15
18
|
def handle_fleet_request(payload, delivery: nil, properties: nil)
|
|
19
|
+
log.debug do
|
|
20
|
+
"bedrock.runner.fleet_worker.handle_fleet_request: request_id=#{payload_value(payload, :request_id)} " \
|
|
21
|
+
"provider_instance=#{payload_value(payload, :provider_instance) || 'default'}"
|
|
22
|
+
end
|
|
16
23
|
Legion::Extensions::Llm::Fleet::ProviderResponder.call(
|
|
17
24
|
payload: payload,
|
|
18
25
|
provider_family: Bedrock::PROVIDER_FAMILY,
|
|
@@ -22,6 +29,12 @@ module Legion
|
|
|
22
29
|
properties: properties
|
|
23
30
|
)
|
|
24
31
|
end
|
|
32
|
+
|
|
33
|
+
def payload_value(payload, key)
|
|
34
|
+
return nil unless payload.respond_to?(:[])
|
|
35
|
+
|
|
36
|
+
payload[key] || payload[key.to_s]
|
|
37
|
+
end
|
|
25
38
|
end
|
|
26
39
|
end
|
|
27
40
|
end
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require 'legion/extensions/llm'
|
|
4
4
|
require 'legion/extensions/llm/bedrock/provider'
|
|
5
5
|
require 'legion/extensions/llm/bedrock/version'
|
|
6
|
+
require 'legion/logging/helper'
|
|
6
7
|
|
|
7
8
|
module Legion
|
|
8
9
|
module Extensions
|
|
@@ -58,6 +59,8 @@ module Legion
|
|
|
58
59
|
@registry_publisher ||= Legion::Extensions::Llm::RegistryPublisher.new(provider_family: PROVIDER_FAMILY)
|
|
59
60
|
end
|
|
60
61
|
|
|
62
|
+
DEFAULT_CAPABILITIES = %i[completion streaming embedding].freeze
|
|
63
|
+
|
|
61
64
|
def self.discover_instances
|
|
62
65
|
candidates = {}
|
|
63
66
|
discover_env_bearer(candidates)
|
|
@@ -65,7 +68,23 @@ module Legion
|
|
|
65
68
|
discover_env_sigv4(candidates)
|
|
66
69
|
discover_settings(candidates)
|
|
67
70
|
discover_broker(candidates)
|
|
68
|
-
CredentialSources.dedup_credentials(candidates)
|
|
71
|
+
CredentialSources.dedup_credentials(candidates)
|
|
72
|
+
.reject { |_, config| unresolved_credential?(config) }
|
|
73
|
+
.transform_values do |config|
|
|
74
|
+
sanitized = sanitize_instance_config(config)
|
|
75
|
+
sanitized[:capabilities] ||= DEFAULT_CAPABILITIES.dup
|
|
76
|
+
sanitized[:default_model] ||= 'us.anthropic.claude-sonnet-4-6'
|
|
77
|
+
sanitized
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def self.unresolved_credential?(config)
|
|
82
|
+
return false if config[:bedrock_profile]
|
|
83
|
+
|
|
84
|
+
cred = config[:bearer_token] || config[:bedrock_access_key_id] || config[:api_key]
|
|
85
|
+
return true if cred.nil?
|
|
86
|
+
|
|
87
|
+
cred.to_s.match?(%r{\A(vault|env)://})
|
|
69
88
|
end
|
|
70
89
|
|
|
71
90
|
def self.discover_env_bearer(candidates)
|
|
@@ -75,7 +94,9 @@ module Legion
|
|
|
75
94
|
candidates[:env_bearer] = {
|
|
76
95
|
bearer_token: bearer,
|
|
77
96
|
bedrock_region: CredentialSources.env('AWS_DEFAULT_REGION') || DEFAULT_REGION,
|
|
78
|
-
tier: :cloud
|
|
97
|
+
tier: :cloud,
|
|
98
|
+
source: CredentialSources.source_tag(:env, 'AWS_BEARER_TOKEN_BEDROCK'),
|
|
99
|
+
credential_fingerprint: CredentialSources.credential_fingerprint(bearer)
|
|
79
100
|
}
|
|
80
101
|
end
|
|
81
102
|
|
|
@@ -87,7 +108,9 @@ module Legion
|
|
|
87
108
|
candidates[:claude] = {
|
|
88
109
|
bearer_token: claude_bearer,
|
|
89
110
|
bedrock_region: CredentialSources.claude_env_value('AWS_DEFAULT_REGION') || DEFAULT_REGION,
|
|
90
|
-
tier: :cloud
|
|
111
|
+
tier: :cloud,
|
|
112
|
+
source: CredentialSources.source_tag(:file, '~/.claude/settings.json', 'AWS_BEARER_TOKEN_BEDROCK'),
|
|
113
|
+
credential_fingerprint: CredentialSources.credential_fingerprint(claude_bearer)
|
|
91
114
|
}
|
|
92
115
|
end
|
|
93
116
|
|
|
@@ -99,7 +122,10 @@ module Legion
|
|
|
99
122
|
candidates[:env_sigv4] = {
|
|
100
123
|
api_key: akid, bedrock_access_key_id: akid, bedrock_secret_access_key: skey,
|
|
101
124
|
bedrock_session_token: CredentialSources.env('AWS_SESSION_TOKEN'),
|
|
102
|
-
bedrock_region: CredentialSources.env('AWS_DEFAULT_REGION') || DEFAULT_REGION,
|
|
125
|
+
bedrock_region: CredentialSources.env('AWS_DEFAULT_REGION') || DEFAULT_REGION,
|
|
126
|
+
tier: :cloud,
|
|
127
|
+
source: CredentialSources.source_tag(:env, 'AWS_ACCESS_KEY_ID'),
|
|
128
|
+
credential_fingerprint: CredentialSources.credential_fingerprint(akid)
|
|
103
129
|
}.compact
|
|
104
130
|
end
|
|
105
131
|
|
|
@@ -108,12 +134,19 @@ module Legion
|
|
|
108
134
|
return unless settings.is_a?(Hash) && !settings.empty?
|
|
109
135
|
|
|
110
136
|
default_config = dedup_config(normalize_instance_config(settings))
|
|
111
|
-
|
|
137
|
+
unless default_config.empty?
|
|
138
|
+
default_config[:source] = CredentialSources.source_tag(:settings, 'extensions.llm.bedrock')
|
|
139
|
+
default_config[:credential_fingerprint] = CredentialSources.config_fingerprint(default_config)
|
|
140
|
+
candidates[:settings] = default_config.merge(tier: :cloud)
|
|
141
|
+
end
|
|
112
142
|
|
|
113
143
|
settings_instances(settings).each do |name, config|
|
|
114
144
|
next unless config.is_a?(Hash)
|
|
115
145
|
|
|
116
|
-
|
|
146
|
+
normalized = dedup_config(normalize_instance_config(config))
|
|
147
|
+
normalized[:source] = CredentialSources.source_tag(:settings, "extensions.llm.bedrock.instances.#{name}")
|
|
148
|
+
normalized[:credential_fingerprint] = CredentialSources.config_fingerprint(normalized)
|
|
149
|
+
candidates[name.to_sym] = normalized.merge(tier: :cloud)
|
|
117
150
|
end
|
|
118
151
|
end
|
|
119
152
|
|
|
@@ -121,7 +154,11 @@ module Legion
|
|
|
121
154
|
return unless defined?(Legion::Identity::Broker)
|
|
122
155
|
|
|
123
156
|
broker_creds = broker_aws_credentials
|
|
124
|
-
|
|
157
|
+
return unless broker_creds
|
|
158
|
+
|
|
159
|
+
broker_creds[:source] = CredentialSources.source_tag(:broker, 'identity', 'aws')
|
|
160
|
+
broker_creds[:credential_fingerprint] = CredentialSources.config_fingerprint(broker_creds)
|
|
161
|
+
candidates[:broker] = broker_creds.merge(tier: :cloud)
|
|
125
162
|
end
|
|
126
163
|
|
|
127
164
|
# Scan Claude config env hash for any key containing all of
|