lex-llm-bedrock 0.3.8 → 0.3.10

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5ef7a8a909bb86688882fc9ffca3c7fd96955d75cb01e5048efa954909599c49
4
- data.tar.gz: 90d58f5f3e6f976b2332341e6f5624064a5b70f7ce5381d4df94b082d7398ab7
3
+ metadata.gz: a0d6ffe6c93fec2590c74ed5a01a944c81694fb98316bf35bde08db6efecfed9
4
+ data.tar.gz: 3e5174849ecf00a36f79e8926237f430ce1b1e8a8572c4fede2463e5cc0a3bda
5
5
  SHA512:
6
- metadata.gz: ab5e3feccaee75a608ba7032721bd899e74e9059bfee3704ebc45b1f1733a5341eb2e1f1f99be48bdc2b0eee4555aaf8985e1c84a2c673474dbc4ae018abf6b7
7
- data.tar.gz: 61b3a978d40a10d91f725ffd3ebc7b937596fa60740fb9e3d168cbba6f19fc2a50f27af56a637612c4980b1e4408dcae61e2148fff6b819026ed35811fbdcf6c
6
+ metadata.gz: 273bc8934934e7eb40e9365a57de5fb33c12114c84b435b353ffb3e0e83329ced120f94016ddc59bd8cfc484c3a35094814f41beb8b0361ece513417505954d5
7
+ data.tar.gz: 2d36dcff70b35577a0d5bbf6846ed6181851e6ac32d8cd65f67367429f32ec88869a084ccc4e3fdde200ab50ae3ca6c21509c84fa7a4af5ae360eaf75b85a2c5
data/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.10 - 2026-05-21
4
+
5
+ - Add `default_transport`/`default_tier` class declarations, remove `configured_transport`/`configured_tier`
6
+ - Add `model_allowed?` filtering in `discover_offerings` (handles ModelOffering objects)
7
+ - Move `DEFAULT_REGION` to settings[:region]
8
+ - Default tier corrected from :frontier to :cloud
9
+ - Identity headers included via base provider
10
+
11
+
12
+ ## 0.3.9 - 2026-05-18
13
+
14
+ - Fix streaming tool call parsing: `stream_converse` now handles content_block_start/delta/stop events for tool_use blocks, capturing tool ids, names, and accumulated input JSON. Previously only text deltas were captured and tool calls were silently dropped.
15
+
16
+
3
17
  ## 0.3.8 - 2026-05-13
4
18
 
5
19
  - Auto-prefix `us.` on `inference_profile_id` for Anthropic, Meta, Mistral, Cohere, and AI21 models at API call time.
@@ -14,8 +14,6 @@ module Legion
14
14
  class Provider < Legion::Extensions::Llm::Provider # rubocop:disable Metrics/ClassLength
15
15
  include Legion::Logging::Helper
16
16
 
17
- DEFAULT_REGION = 'us-east-1'
18
-
19
17
  STATIC_MODELS = [
20
18
  { model: 'anthropic.claude-3-haiku-20240307-v1:0', alias: 'claude-3-haiku' },
21
19
  { model: 'amazon.titan-text-express-v1', alias: 'titan-text-express' },
@@ -50,6 +48,8 @@ module Legion
50
48
 
51
49
  class << self
52
50
  def slug = 'bedrock'
51
+ def default_transport = :aws_sdk
52
+ def default_tier = :cloud
53
53
 
54
54
  def configuration_options
55
55
  %i[
@@ -113,7 +113,7 @@ module Legion
113
113
  def count_tokens_url = 'CountTokens'
114
114
 
115
115
  def region
116
- config.bedrock_region || DEFAULT_REGION
116
+ config.bedrock_region || settings[:region] || 'us-east-1'
117
117
  end
118
118
 
119
119
  def discover_offerings(live: false, **filters)
@@ -126,8 +126,12 @@ module Legion
126
126
 
127
127
  log.info { "bedrock.provider.discover_offerings: listing foundation models (region=#{region})" }
128
128
  response = bedrock_client.list_foundation_models(**filters)
129
- @cached_offerings = Array(value(response, :model_summaries)).map do |summary|
130
- offering_from_summary(summary)
129
+ @cached_offerings = Array(value(response, :model_summaries)).filter_map do |summary|
130
+ offering = offering_from_summary(summary)
131
+ model_id = offering.respond_to?(:model) ? offering.model : (offering[:model] || offering[:id])
132
+ next unless model_allowed?(model_id.to_s)
133
+
134
+ offering
131
135
  end
132
136
  log.info { "bedrock.provider.discover_offerings: found #{@cached_offerings.size} models" }
133
137
  @cached_offerings
@@ -323,8 +327,8 @@ module Legion
323
327
  Legion::Extensions::Llm::Routing::ModelOffering.new(
324
328
  provider_family: :bedrock,
325
329
  instance_id: instance_id,
326
- transport: configured_transport(:aws_sdk),
327
- tier: configured_tier(:frontier),
330
+ transport: offering_transport,
331
+ tier: offering_tier,
328
332
  model: model,
329
333
  usage_type: usage_type,
330
334
  capabilities: capabilities || default_capabilities(model),
@@ -346,14 +350,6 @@ module Legion
346
350
  ctx ? { context_window: ctx } : nil
347
351
  end
348
352
 
349
- def configured_transport(default)
350
- config.respond_to?(:transport) ? config.transport : default
351
- end
352
-
353
- def configured_tier(default)
354
- config.respond_to?(:tier) ? config.tier : default
355
- end
356
-
357
353
  def converse_request(messages, model:, temperature:, max_tokens:, tools:, tool_prefs:)
358
354
  {
359
355
  model_id: self.class.inference_profile_id(model_id(model)),
@@ -474,30 +470,99 @@ module Legion
474
470
  end
475
471
 
476
472
  def stream_converse(request, fallback_model)
477
- accumulated = +''
478
- final_usage = nil
473
+ state = { accumulated: +'', final_usage: nil, stop_reason: nil, tool_use_blocks: [], current_tool_use: nil }
479
474
 
480
475
  runtime_client.converse_stream(**request) do |stream|
481
- stream.on_content_block_delta_event do |event|
482
- text = value(value(event, :delta), :text)
483
- next if text.nil?
476
+ wire_stream_handlers(stream, state, fallback_model) { |chunk| yield chunk if block_given? }
477
+ end
478
+
479
+ Legion::Extensions::Llm::Message.new(
480
+ role: :assistant,
481
+ content: state[:accumulated],
482
+ model_id: fallback_model,
483
+ tool_calls: build_stream_tool_calls(state[:tool_use_blocks]),
484
+ input_tokens: value(state[:final_usage], :input_tokens),
485
+ output_tokens: value(state[:final_usage], :output_tokens),
486
+ stop_reason: state[:stop_reason]
487
+ )
488
+ end
489
+
490
+ def wire_stream_handlers(stream, state, fallback_model, &)
491
+ wire_block_start(stream, state)
492
+ wire_block_delta(stream, state, fallback_model, &)
493
+ wire_block_stop(stream, state)
494
+ wire_message_stop(stream, state)
495
+ stream.on_metadata_event { |event| state[:final_usage] = value(event, :usage) }
496
+ end
497
+
498
+ def wire_block_start(stream, state)
499
+ return unless stream.respond_to?(:on_content_block_start_event)
500
+
501
+ stream.on_content_block_start_event do |event|
502
+ start = value(event, :start)
503
+ tool_start = value(start, :tool_use) if start
504
+ next unless tool_start
505
+
506
+ state[:current_tool_use] = {
507
+ tool_use_id: value(tool_start, :tool_use_id),
508
+ name: value(tool_start, :name),
509
+ input_json: +''
510
+ }
511
+ end
512
+ end
484
513
 
485
- accumulated << text
514
+ def wire_block_delta(stream, state, fallback_model)
515
+ stream.on_content_block_delta_event do |event|
516
+ delta = value(event, :delta)
517
+ text = value(delta, :text)
518
+ if text
519
+ state[:accumulated] << text
486
520
  if block_given?
487
521
  yield Legion::Extensions::Llm::Chunk.new(role: :assistant, content: text,
488
522
  model_id: fallback_model)
489
523
  end
490
524
  end
491
- stream.on_metadata_event { |event| final_usage = value(event, :usage) }
525
+
526
+ tool_input = value(delta, :tool_use)
527
+ next unless tool_input && state[:current_tool_use]
528
+
529
+ input_chunk = value(tool_input, :input)
530
+ state[:current_tool_use][:input_json] << input_chunk.to_s if input_chunk
492
531
  end
532
+ end
493
533
 
494
- Legion::Extensions::Llm::Message.new(
495
- role: :assistant,
496
- content: accumulated,
497
- model_id: fallback_model,
498
- input_tokens: value(final_usage, :input_tokens),
499
- output_tokens: value(final_usage, :output_tokens)
500
- )
534
+ def wire_block_stop(stream, state)
535
+ return unless stream.respond_to?(:on_content_block_stop_event)
536
+
537
+ stream.on_content_block_stop_event do |_event|
538
+ next unless state[:current_tool_use]
539
+
540
+ state[:tool_use_blocks] << state[:current_tool_use]
541
+ state[:current_tool_use] = nil
542
+ end
543
+ end
544
+
545
+ def wire_message_stop(stream, state)
546
+ return unless stream.respond_to?(:on_message_stop_event)
547
+
548
+ stream.on_message_stop_event do |event|
549
+ state[:stop_reason] = value(event, :stop_reason)
550
+ end
551
+ end
552
+
553
+ def build_stream_tool_calls(tool_use_blocks)
554
+ return nil if tool_use_blocks.empty?
555
+
556
+ tool_use_blocks.to_h do |block|
557
+ input = begin
558
+ Legion::JSON.load(block[:input_json])
559
+ rescue StandardError
560
+ {}
561
+ end
562
+ name = block[:name]
563
+ id = block[:tool_use_id] || name
564
+ [id, Legion::Extensions::Llm::ToolCall.new(id: id, name: name, arguments: input)]
565
+ end
501
566
  end
502
567
 
503
568
  def parse_embedding_response(response, model:)
@@ -4,7 +4,7 @@ module Legion
4
4
  module Extensions
5
5
  module Llm
6
6
  module Bedrock
7
- VERSION = '0.3.8'
7
+ VERSION = '0.3.10'
8
8
  end
9
9
  end
10
10
  end
@@ -23,7 +23,8 @@ module Legion
23
23
  family: PROVIDER_FAMILY,
24
24
  instance: {
25
25
  default_model: 'us.anthropic.claude-sonnet-4-6',
26
- tier: :frontier,
26
+ region: 'us-east-1',
27
+ tier: :cloud,
27
28
  transport: :aws_sdk,
28
29
  credentials: {
29
30
  bearer_token: nil,
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lex-llm-bedrock
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.8
4
+ version: 0.3.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - LegionIO