lex-llm-bedrock 0.3.19 → 0.4.3
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/.rubocop.yml +4 -0
- data/CHANGELOG.md +30 -0
- data/Gemfile +0 -7
- data/lex-llm-bedrock.gemspec +1 -1
- data/lib/legion/extensions/llm/bedrock/actors/discovery_refresh.rb +7 -0
- data/lib/legion/extensions/llm/bedrock/provider.rb +140 -18
- data/lib/legion/extensions/llm/bedrock/translator.rb +899 -0
- data/lib/legion/extensions/llm/bedrock/version.rb +1 -1
- data/lib/legion/extensions/llm/bedrock.rb +4 -6
- metadata +4 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 05badbea355fec879dbd270070928472682c35d8709e3e6336e0080ca00aeb36
|
|
4
|
+
data.tar.gz: ec34813a7de565ad347c95777715054d27bd53ce71b04d8ddfd57de149852c9e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: '073218f79b092a425703aa62f45b8d07d69afcf01d1249b66435fa4dce7211f74cbfab184e7df61f506f92c0ca4322d1d8448e6317ed5d52870d699ff42757e9'
|
|
7
|
+
data.tar.gz: 415524d66dcb863b18036935b15b7965996adb249d78779845b6f53679e22745b9316a438de386e490051cf7c46af6bc3264cf3db24d2b7517a7c5c4d49c9375
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.3 - 2026-06-16
|
|
4
|
+
|
|
5
|
+
- Dependency updates and code quality improvements.
|
|
6
|
+
|
|
7
|
+
## 0.4.2 - 2026-06-15
|
|
8
|
+
|
|
9
|
+
- **CapabilityPolicy integration** — AWS model summaries used as `:model_metadata`; Converse tool use from `:provider_envelope`. Settings overrides at provider/instance/model level supported.
|
|
10
|
+
|
|
11
|
+
## 0.4.1 - 2026-06-13
|
|
12
|
+
|
|
13
|
+
- **Gemfile cleanup** — Remove local path overrides; dependencies resolve from gemspec via rubygems.
|
|
14
|
+
- **RuboCop fixes** — Auto-corrected 6 offenses (style/layout).
|
|
15
|
+
- 199 examples, 0 failures; 17 files, 0 rubocop offenses.
|
|
16
|
+
|
|
17
|
+
## 0.4.0 - 2026-06-10
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
- **Canonical provider translator** — New `Legion::Extensions::Llm::Bedrock::Translator` class implementing the canonical translator interface per Phase 3 of the N×N routing design. Supports `render_request`, `parse_response`, `parse_chunk`, and `capabilities`. Extracted from existing `format_messages`, `format_tools`, `parse_*` provider code (provider.rb) — move and normalize, no semantic rewrites.
|
|
21
|
+
- **Dual render targets** — Translator renders canonical requests to both Bedrock Converse API (`:converse`) and Bedrock invoke_model with Anthropic Messages payload (`:invoke_model`). Auto-selection: Anthropic models with thinking or tools route through invoke_model, all other requests use Converse.
|
|
22
|
+
- **Conformance kit adoption** — Loads `it_behaves_like 'a canonical provider translator'` shared examples from lex-llm. Full fixture-driven conformance with simple text, system prompt, params, tools, thinking, multi-turn continuation, streaming (text/thinking/tool call), error, stop_reason mapping, and round-trip consistency.
|
|
23
|
+
- **Canonical capabilities declaration** — `capabilities` declares `provider: 'bedrock'`, `render_targets: [:converse, :invoke_model]`, `thinking: :budget_tokens`, `stop_reasons` mapping (including `guardrail_intervened` → `content_filter`).
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
- **lex-llm dependency** — Bumped to `lex-llm >= 0.5.0` for canonical types (Request/Response/Chunk/Params/Thinking/ToolCall/Usage/Message/ContentBlock/ToolDefinition) and conformance kit availability.
|
|
27
|
+
- **Version bump** — Minor version 0.3.x → 0.4.0 (additive feature release).
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
- **Params handling** — Translator uses `Canonical::Params.from_hash` instead of non-existent `Params.build`. All 187 specs pass.
|
|
31
|
+
- **Content block type/Access** — Translator correctly handles both Hash-inputs and `Canonical::ContentBlock` Data-struct objects with `.type`/`.text` attribute accessors.
|
|
32
|
+
|
|
3
33
|
## 0.3.19 - 2026-06-10
|
|
4
34
|
|
|
5
35
|
### Fixed
|
data/Gemfile
CHANGED
|
@@ -2,13 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
source 'https://rubygems.org'
|
|
4
4
|
|
|
5
|
-
group :test do
|
|
6
|
-
llm_base_path = ENV.fetch('LEX_LLM_PATH', File.expand_path('../lex-llm', __dir__))
|
|
7
|
-
transport_path = ENV.fetch('LEGION_TRANSPORT_PATH', File.expand_path('../../legion-transport', __dir__))
|
|
8
|
-
gem 'legion-transport', path: transport_path if File.directory?(transport_path)
|
|
9
|
-
gem 'lex-llm', path: llm_base_path if File.directory?(llm_base_path)
|
|
10
|
-
end
|
|
11
|
-
|
|
12
5
|
gemspec
|
|
13
6
|
|
|
14
7
|
group :development do
|
data/lex-llm-bedrock.gemspec
CHANGED
|
@@ -29,5 +29,5 @@ Gem::Specification.new do |spec|
|
|
|
29
29
|
spec.add_dependency 'legion-logging', '>= 1.3.2'
|
|
30
30
|
spec.add_dependency 'legion-settings', '>= 1.3.14'
|
|
31
31
|
spec.add_dependency 'legion-transport', '>= 1.4.14'
|
|
32
|
-
spec.add_dependency 'lex-llm', '>= 0.
|
|
32
|
+
spec.add_dependency 'lex-llm', '>= 0.5.0'
|
|
33
33
|
end
|
|
@@ -36,6 +36,13 @@ module Legion
|
|
|
36
36
|
return unless defined?(Legion::LLM::Discovery)
|
|
37
37
|
|
|
38
38
|
Legion::LLM::Discovery.refresh_discovered_models!(provider: :bedrock)
|
|
39
|
+
|
|
40
|
+
if defined?(Legion::LLM::Router) && Legion::LLM::Router.respond_to?(:populate_auto_rules)
|
|
41
|
+
Legion::LLM::Router.populate_auto_rules(Legion::LLM::Discovery.discovered_instances)
|
|
42
|
+
end
|
|
43
|
+
if defined?(Legion::LLM::Inventory) && Legion::LLM::Inventory.respond_to?(:invalidate_offerings_cache!)
|
|
44
|
+
Legion::LLM::Inventory.invalidate_offerings_cache!
|
|
45
|
+
end
|
|
39
46
|
rescue StandardError => e
|
|
40
47
|
handle_exception(e, level: :warn, handled: true, operation: 'bedrock.actor.discovery_refresh')
|
|
41
48
|
end
|
|
@@ -11,6 +11,8 @@ module Legion
|
|
|
11
11
|
module Extensions
|
|
12
12
|
module Llm
|
|
13
13
|
module Bedrock
|
|
14
|
+
class StaticCredentialsBlockedError < Legion::Extensions::Llm::ConfigurationError; end
|
|
15
|
+
|
|
14
16
|
# Amazon Bedrock provider implementation for the Legion::Extensions::Llm contract.
|
|
15
17
|
class Provider < Legion::Extensions::Llm::Provider # rubocop:disable Metrics/ClassLength
|
|
16
18
|
include Legion::Logging::Helper
|
|
@@ -18,6 +20,10 @@ module Legion
|
|
|
18
20
|
STATIC_MODELS = [
|
|
19
21
|
{ model: 'anthropic.claude-3-haiku-20240307-v1:0', alias: 'claude-3-haiku' },
|
|
20
22
|
{ model: 'anthropic.claude-sonnet-4-20250514-v1:0', alias: 'anthropic.claude-sonnet-4' },
|
|
23
|
+
{ model: 'anthropic.claude-sonnet-4-20250514-v1:0', alias: 'claude-sonnet-4-6' },
|
|
24
|
+
{ model: 'anthropic.claude-sonnet-4-20250514-v1:0', alias: 'claude-sonnet-4-5-20241022' },
|
|
25
|
+
{ model: 'anthropic.claude-opus-4-20250515-v1:0', alias: 'claude-opus-4-8' },
|
|
26
|
+
{ model: 'anthropic.claude-haiku-4-20250506-v1:0', alias: 'claude-haiku-4-5' },
|
|
21
27
|
{ model: 'amazon.titan-text-express-v1', alias: 'titan-text-express' },
|
|
22
28
|
{ model: 'amazon.titan-embed-text-v2:0', alias: 'titan-embed-text-v2', usage_type: :embedding },
|
|
23
29
|
{ model: 'meta.llama3-2-11b-instruct-v1:0', alias: 'llama-3.2-11b-instruct' },
|
|
@@ -117,6 +123,10 @@ module Legion
|
|
|
117
123
|
end
|
|
118
124
|
end
|
|
119
125
|
|
|
126
|
+
def translator
|
|
127
|
+
@translator ||= Translator.new(region: region)
|
|
128
|
+
end
|
|
129
|
+
|
|
120
130
|
def api_base
|
|
121
131
|
config.bedrock_endpoint || "https://bedrock-runtime.#{region}.amazonaws.com"
|
|
122
132
|
end
|
|
@@ -499,8 +509,15 @@ module Legion
|
|
|
499
509
|
state[:raw_events] << { event: event_type, data: raw_event } if dump_path
|
|
500
510
|
handle_invoke_model_stream_json(raw_event, state, mid) { |chunk| yield chunk if block_given? }
|
|
501
511
|
end
|
|
512
|
+
rescue Legion::JSON::ParseError => e
|
|
513
|
+
handle_exception(e, level: :warn, handled: true,
|
|
514
|
+
operation: 'bedrock.provider.invoke_model_stream.chunk_decode')
|
|
502
515
|
rescue StandardError => e
|
|
503
|
-
|
|
516
|
+
# Never swallow non-parse errors here — a silent rescue in this
|
|
517
|
+
# event handler previously hid streaming bugs as dead-air streams.
|
|
518
|
+
handle_exception(e, level: :error, handled: false,
|
|
519
|
+
operation: 'bedrock.provider.invoke_model_stream.chunk_event')
|
|
520
|
+
raise
|
|
504
521
|
end
|
|
505
522
|
|
|
506
523
|
stream.on_error_event do |event|
|
|
@@ -555,12 +572,14 @@ module Legion
|
|
|
555
572
|
Legion::Extensions::Llm::Message.new(**msg_attrs)
|
|
556
573
|
end
|
|
557
574
|
|
|
558
|
-
def build_invoke_model_body(messages:, temperature:, max_tokens:, tools:, tool_prefs:, thinking:, **
|
|
575
|
+
def build_invoke_model_body(messages:, temperature:, max_tokens:, tools:, tool_prefs:, thinking:, **rest)
|
|
576
|
+
system_content = extract_invoke_model_system(messages, system: rest[:system])
|
|
559
577
|
body = {
|
|
560
578
|
max_tokens: max_tokens || 4096,
|
|
561
579
|
messages: format_invoke_model_messages(messages),
|
|
562
580
|
anthropic_version: 'bedrock-2023-05-31'
|
|
563
581
|
}
|
|
582
|
+
body[:system] = system_content if system_content
|
|
564
583
|
body[:temperature] = temperature if temperature
|
|
565
584
|
if tools && !tools.empty?
|
|
566
585
|
tool_format = format_invoke_model_tools(tools, tool_prefs)
|
|
@@ -568,11 +587,25 @@ module Legion
|
|
|
568
587
|
body[:tool_choice] = tool_format[:tool_choice] if tool_format[:tool_choice]
|
|
569
588
|
end
|
|
570
589
|
body[:thinking] = invoke_model_thinking(thinking) if thinking
|
|
571
|
-
# NOTE: Don't include body[:stream] = true in the JSON body for invoke_model_with_response_stream.
|
|
572
|
-
# The endpoint itself implies streaming; Bedrock rejects the extra field.
|
|
573
590
|
body
|
|
574
591
|
end
|
|
575
592
|
|
|
593
|
+
def extract_invoke_model_system(messages, system: nil)
|
|
594
|
+
parts = []
|
|
595
|
+
parts << system.to_s unless system.to_s.empty?
|
|
596
|
+
messages.each do |msg|
|
|
597
|
+
role = msg.respond_to?(:role) ? msg.role.to_s : (msg[:role] || msg['role']).to_s
|
|
598
|
+
next unless role == 'system'
|
|
599
|
+
|
|
600
|
+
content = msg.respond_to?(:content) ? msg.content : (msg[:content] || msg['content'])
|
|
601
|
+
text = content.is_a?(Array) ? content.filter_map { |b| b[:text] || b['text'] }.join("\n") : content.to_s
|
|
602
|
+
parts << text unless text.empty?
|
|
603
|
+
end
|
|
604
|
+
return nil if parts.empty?
|
|
605
|
+
|
|
606
|
+
parts.map { |t| { type: 'text', text: t } }
|
|
607
|
+
end
|
|
608
|
+
|
|
576
609
|
# Strip provider-specific keys (e.g. effort from OpenAI) that Bedrock/Anthropic APIs don't accept.
|
|
577
610
|
def invoke_model_thinking(thinking)
|
|
578
611
|
return thinking unless thinking.is_a?(Hash)
|
|
@@ -581,7 +614,7 @@ module Legion
|
|
|
581
614
|
end
|
|
582
615
|
|
|
583
616
|
def format_invoke_model_messages(messages)
|
|
584
|
-
messages.filter_map do |msg|
|
|
617
|
+
formatted = messages.filter_map do |msg|
|
|
585
618
|
role = msg.respond_to?(:role) ? msg.role.to_s : (msg[:role] || msg['role']).to_s
|
|
586
619
|
next if role == 'system'
|
|
587
620
|
|
|
@@ -598,6 +631,19 @@ module Legion
|
|
|
598
631
|
|
|
599
632
|
{ role: role == 'tool' ? 'user' : role, content: content }
|
|
600
633
|
end
|
|
634
|
+
consolidate_adjacent_roles(formatted)
|
|
635
|
+
end
|
|
636
|
+
|
|
637
|
+
def consolidate_adjacent_roles(messages)
|
|
638
|
+
return messages if messages.size < 2
|
|
639
|
+
|
|
640
|
+
messages.each_with_object([]) do |msg, result|
|
|
641
|
+
if result.last && result.last[:role] == msg[:role]
|
|
642
|
+
result.last[:content] = Array(result.last[:content]) + Array(msg[:content])
|
|
643
|
+
else
|
|
644
|
+
result << msg
|
|
645
|
+
end
|
|
646
|
+
end
|
|
601
647
|
end
|
|
602
648
|
|
|
603
649
|
def format_invoke_model_content(msg)
|
|
@@ -664,11 +710,11 @@ module Legion
|
|
|
664
710
|
|
|
665
711
|
def format_invoke_model_tools(tools, tool_prefs)
|
|
666
712
|
tool_list = tools.values.map do |tool|
|
|
713
|
+
raw_schema = tool[:params_schema] || tool['params_schema'] || tool[:parameters] || tool['parameters']
|
|
667
714
|
{
|
|
668
715
|
name: tool[:name] || tool['name'],
|
|
669
716
|
description: tool[:description] || tool['description'] || '',
|
|
670
|
-
input_schema:
|
|
671
|
-
{ type: 'object', properties: {} }
|
|
717
|
+
input_schema: Legion::Extensions::Llm::Canonical::ToolDefinition.normalize_parameters(raw_schema)
|
|
672
718
|
}
|
|
673
719
|
end
|
|
674
720
|
|
|
@@ -802,7 +848,11 @@ module Legion
|
|
|
802
848
|
state[:stop_reason] = delta['stop_reason']
|
|
803
849
|
end
|
|
804
850
|
rescue StandardError => e
|
|
805
|
-
|
|
851
|
+
# Re-raise — a swallowed error here turns a streaming bug into a
|
|
852
|
+
# silent dead-air stream (message_start then nothing).
|
|
853
|
+
handle_exception(e, level: :error, handled: false,
|
|
854
|
+
operation: 'bedrock.provider.invoke_model_stream_json')
|
|
855
|
+
raise
|
|
806
856
|
end
|
|
807
857
|
|
|
808
858
|
def static_offerings(**filters)
|
|
@@ -816,12 +866,24 @@ module Legion
|
|
|
816
866
|
|
|
817
867
|
def offering_from_summary(summary)
|
|
818
868
|
model = value(summary, :model_id)
|
|
869
|
+
real = real_capabilities_from_summary(summary)
|
|
870
|
+
policy = Legion::Extensions::Llm::CapabilityPolicy.resolve(
|
|
871
|
+
real: real,
|
|
872
|
+
provider_catalog: {},
|
|
873
|
+
probe: {},
|
|
874
|
+
provider_envelope: provider_envelope_capabilities,
|
|
875
|
+
provider_config: provider_capability_config,
|
|
876
|
+
instance_config: instance_capability_config,
|
|
877
|
+
model_config: model_capability_config(model)
|
|
878
|
+
)
|
|
879
|
+
|
|
819
880
|
build_offering(
|
|
820
881
|
model: model,
|
|
821
882
|
alias_name: alias_for(model),
|
|
822
883
|
model_family: normalize_provider(value(summary, :provider_name)) || model_family_for(model),
|
|
823
884
|
usage_type: usage_type_from_modalities(value(summary, :output_modalities)),
|
|
824
|
-
capabilities:
|
|
885
|
+
capabilities: policy[:capabilities],
|
|
886
|
+
capability_sources: policy[:sources],
|
|
825
887
|
metadata: normalize_response(summary)
|
|
826
888
|
)
|
|
827
889
|
end
|
|
@@ -844,7 +906,7 @@ module Legion
|
|
|
844
906
|
end
|
|
845
907
|
|
|
846
908
|
def build_offering(model:, model_family:, usage_type:, instance_id: :default, alias_name: nil,
|
|
847
|
-
capabilities: nil, metadata: {})
|
|
909
|
+
capabilities: nil, capability_sources: nil, metadata: {})
|
|
848
910
|
limits = infer_limits(model)
|
|
849
911
|
Legion::Extensions::Llm::Routing::ModelOffering.new(
|
|
850
912
|
provider_family: :bedrock,
|
|
@@ -854,6 +916,7 @@ module Legion
|
|
|
854
916
|
model: model,
|
|
855
917
|
usage_type: usage_type,
|
|
856
918
|
capabilities: capabilities || default_capabilities(model),
|
|
919
|
+
capability_sources: capability_sources,
|
|
857
920
|
limits: limits,
|
|
858
921
|
metadata: metadata.merge(model_family: model_family, alias: alias_name).compact
|
|
859
922
|
)
|
|
@@ -903,13 +966,14 @@ module Legion
|
|
|
903
966
|
|
|
904
967
|
def format_messages(messages)
|
|
905
968
|
total = messages.size
|
|
906
|
-
messages.filter_map.with_index do |message, idx|
|
|
969
|
+
formatted = messages.filter_map.with_index do |message, idx|
|
|
907
970
|
blocks = build_content_blocks(message)
|
|
908
971
|
next if blocks.empty?
|
|
909
972
|
|
|
910
973
|
cache_blocks = should_cache_message?(idx, total) ? add_cache_control_to_blocks(blocks) : blocks
|
|
911
974
|
{ role: bedrock_role(message.role), content: cache_blocks }
|
|
912
975
|
end
|
|
976
|
+
consolidate_adjacent_roles(formatted)
|
|
913
977
|
end
|
|
914
978
|
|
|
915
979
|
def tool_result_blocks(message)
|
|
@@ -967,7 +1031,9 @@ module Legion
|
|
|
967
1031
|
text = content_text(message.content)
|
|
968
1032
|
blocks << { text: text } if text && !text.strip.empty?
|
|
969
1033
|
|
|
970
|
-
|
|
1034
|
+
# Array is canonical (name-keyed hashes dropped parallel same-name calls)
|
|
1035
|
+
calls = message.tool_calls.is_a?(Hash) ? message.tool_calls.values : Array(message.tool_calls)
|
|
1036
|
+
calls.each do |call|
|
|
971
1037
|
blocks << {
|
|
972
1038
|
tool_use: {
|
|
973
1039
|
tool_use_id: call.id,
|
|
@@ -1062,9 +1128,12 @@ module Legion
|
|
|
1062
1128
|
end
|
|
1063
1129
|
|
|
1064
1130
|
def tool_schema(tool)
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1131
|
+
raw = if tool.respond_to?(:params_schema) && tool.params_schema
|
|
1132
|
+
tool.params_schema
|
|
1133
|
+
elsif tool.respond_to?(:parameters)
|
|
1134
|
+
tool.parameters
|
|
1135
|
+
end
|
|
1136
|
+
Legion::Extensions::Llm::Canonical::ToolDefinition.normalize_parameters(raw)
|
|
1068
1137
|
end
|
|
1069
1138
|
|
|
1070
1139
|
def tool_choice(tool_prefs)
|
|
@@ -1273,8 +1342,8 @@ module Legion
|
|
|
1273
1342
|
# Bedrock streaming: text blocks use delta.text,
|
|
1274
1343
|
# reasoning/thinking blocks use delta.reasoning.text or delta.thinking.text
|
|
1275
1344
|
text = value(delta, :text) ||
|
|
1276
|
-
(value(delta, :reasoning)
|
|
1277
|
-
(value(delta, :thinking)
|
|
1345
|
+
value(value(delta, :reasoning), :text) ||
|
|
1346
|
+
value(value(delta, :thinking), :text)
|
|
1278
1347
|
if text
|
|
1279
1348
|
if state[:in_thinking]
|
|
1280
1349
|
state[:thinking] << text
|
|
@@ -1399,7 +1468,7 @@ module Legion
|
|
|
1399
1468
|
return nil unless config.bedrock_access_key_id
|
|
1400
1469
|
|
|
1401
1470
|
if static_credentials_blocked?
|
|
1402
|
-
raise
|
|
1471
|
+
raise StaticCredentialsBlockedError,
|
|
1403
1472
|
'Static AWS credentials are disabled (security.block_static_aws_credentials=true); use IAM roles'
|
|
1404
1473
|
end
|
|
1405
1474
|
log.warn('[bedrock] Using static AWS credentials — prefer IAM roles for production')
|
|
@@ -1467,6 +1536,59 @@ module Legion
|
|
|
1467
1536
|
caps
|
|
1468
1537
|
end
|
|
1469
1538
|
|
|
1539
|
+
def real_capabilities_from_summary(summary)
|
|
1540
|
+
caps = {}
|
|
1541
|
+
caps[:streaming] = true if value(summary, :response_streaming_supported)
|
|
1542
|
+
input_mods = Array(value(summary, :input_modalities)).map { |m| m.to_s.upcase }
|
|
1543
|
+
caps[:vision] = true if input_mods.include?('IMAGE')
|
|
1544
|
+
output_mods = Array(value(summary, :output_modalities)).map { |m| m.to_s.upcase }
|
|
1545
|
+
caps[:embeddings] = true if output_mods.include?('EMBEDDING')
|
|
1546
|
+
caps
|
|
1547
|
+
end
|
|
1548
|
+
|
|
1549
|
+
def provider_envelope_capabilities
|
|
1550
|
+
# Bedrock Converse API supports tool use across all active chat model families
|
|
1551
|
+
{ tools: true }
|
|
1552
|
+
end
|
|
1553
|
+
|
|
1554
|
+
def provider_capability_config
|
|
1555
|
+
return {} unless defined?(Legion::Extensions::Llm::CredentialSources)
|
|
1556
|
+
|
|
1557
|
+
conf = Legion::Extensions::Llm::CredentialSources.setting(:extensions, :llm, :bedrock)
|
|
1558
|
+
conf.is_a?(Hash) ? conf.to_h.except(:instances, 'instances') : {}
|
|
1559
|
+
rescue StandardError => e
|
|
1560
|
+
handle_exception(e, level: :debug, handled: true, operation: 'bedrock.provider_capability_config')
|
|
1561
|
+
{}
|
|
1562
|
+
end
|
|
1563
|
+
|
|
1564
|
+
def instance_capability_config
|
|
1565
|
+
cfg = config
|
|
1566
|
+
result = {}
|
|
1567
|
+
%i[capabilities enable_thinking enable_tools enable_streaming enable_vision enable_embeddings
|
|
1568
|
+
thinking_flag tools_flag streaming_flag vision_flag embedding_flag embeddings_flag
|
|
1569
|
+
tool_flag images_flag image_flag].each do |key|
|
|
1570
|
+
next unless cfg.respond_to?(key)
|
|
1571
|
+
|
|
1572
|
+
val = cfg.send(key)
|
|
1573
|
+
result[key] = val unless val.nil?
|
|
1574
|
+
rescue StandardError
|
|
1575
|
+
next
|
|
1576
|
+
end
|
|
1577
|
+
result
|
|
1578
|
+
end
|
|
1579
|
+
|
|
1580
|
+
def model_capability_config(model_id)
|
|
1581
|
+
models_conf = nil
|
|
1582
|
+
models_conf = config.models if config.respond_to?(:models)
|
|
1583
|
+
models_conf ||= config[:models] if config.respond_to?(:[])
|
|
1584
|
+
return {} unless models_conf.respond_to?(:to_h)
|
|
1585
|
+
|
|
1586
|
+
models_conf.to_h[model_id.to_s] || models_conf.to_h[model_id.to_sym] || {}
|
|
1587
|
+
rescue StandardError => e
|
|
1588
|
+
handle_exception(e, level: :debug, handled: true, operation: 'bedrock.model_capability_config')
|
|
1589
|
+
{}
|
|
1590
|
+
end
|
|
1591
|
+
|
|
1470
1592
|
def model_family_for(model)
|
|
1471
1593
|
normalize_provider(model.to_s.split('.').first)
|
|
1472
1594
|
end
|