lex-llm-bedrock 0.3.8 → 0.3.9

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: 1d0b15f1168f45e6f11211963cc8c0939085562bd92e720bcd74426367824318
4
+ data.tar.gz: e68d8865e321e62f0b7c54cf16a573286174626531229b325e53b0aecbc8c3ea
5
5
  SHA512:
6
- metadata.gz: ab5e3feccaee75a608ba7032721bd899e74e9059bfee3704ebc45b1f1733a5341eb2e1f1f99be48bdc2b0eee4555aaf8985e1c84a2c673474dbc4ae018abf6b7
7
- data.tar.gz: 61b3a978d40a10d91f725ffd3ebc7b937596fa60740fb9e3d168cbba6f19fc2a50f27af56a637612c4980b1e4408dcae61e2148fff6b819026ed35811fbdcf6c
6
+ metadata.gz: ac5ed2ff6e4d586891edc3d05a8935cd32b25b561862a882c04a17d2c42324f8cfde527338c8d464cc8373d06dfa4b758fc3a7ab4c1ac70072d22d9998799207
7
+ data.tar.gz: 1e6f4bd752aa5fe9eeb033426405718826135763e2f6974674a7238ffbf74134024ad8f164962d02dc908aa8276417451087c7092e623beda5e0df58977efbf4
data/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.9 - 2026-05-18
4
+
5
+ - 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.
6
+
7
+
3
8
  ## 0.3.8 - 2026-05-13
4
9
 
5
10
  - Auto-prefix `us.` on `inference_profile_id` for Anthropic, Meta, Mistral, Cohere, and AI21 models at API call time.
@@ -474,30 +474,99 @@ module Legion
474
474
  end
475
475
 
476
476
  def stream_converse(request, fallback_model)
477
- accumulated = +''
478
- final_usage = nil
477
+ state = { accumulated: +'', final_usage: nil, stop_reason: nil, tool_use_blocks: [], current_tool_use: nil }
479
478
 
480
479
  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?
480
+ wire_stream_handlers(stream, state, fallback_model) { |chunk| yield chunk if block_given? }
481
+ end
482
+
483
+ Legion::Extensions::Llm::Message.new(
484
+ role: :assistant,
485
+ content: state[:accumulated],
486
+ model_id: fallback_model,
487
+ tool_calls: build_stream_tool_calls(state[:tool_use_blocks]),
488
+ input_tokens: value(state[:final_usage], :input_tokens),
489
+ output_tokens: value(state[:final_usage], :output_tokens),
490
+ stop_reason: state[:stop_reason]
491
+ )
492
+ end
493
+
494
+ def wire_stream_handlers(stream, state, fallback_model, &)
495
+ wire_block_start(stream, state)
496
+ wire_block_delta(stream, state, fallback_model, &)
497
+ wire_block_stop(stream, state)
498
+ wire_message_stop(stream, state)
499
+ stream.on_metadata_event { |event| state[:final_usage] = value(event, :usage) }
500
+ end
484
501
 
485
- accumulated << text
502
+ def wire_block_start(stream, state)
503
+ return unless stream.respond_to?(:on_content_block_start_event)
504
+
505
+ stream.on_content_block_start_event do |event|
506
+ start = value(event, :start)
507
+ tool_start = value(start, :tool_use) if start
508
+ next unless tool_start
509
+
510
+ state[:current_tool_use] = {
511
+ tool_use_id: value(tool_start, :tool_use_id),
512
+ name: value(tool_start, :name),
513
+ input_json: +''
514
+ }
515
+ end
516
+ end
517
+
518
+ def wire_block_delta(stream, state, fallback_model)
519
+ stream.on_content_block_delta_event do |event|
520
+ delta = value(event, :delta)
521
+ text = value(delta, :text)
522
+ if text
523
+ state[:accumulated] << text
486
524
  if block_given?
487
525
  yield Legion::Extensions::Llm::Chunk.new(role: :assistant, content: text,
488
526
  model_id: fallback_model)
489
527
  end
490
528
  end
491
- stream.on_metadata_event { |event| final_usage = value(event, :usage) }
529
+
530
+ tool_input = value(delta, :tool_use)
531
+ next unless tool_input && state[:current_tool_use]
532
+
533
+ input_chunk = value(tool_input, :input)
534
+ state[:current_tool_use][:input_json] << input_chunk.to_s if input_chunk
492
535
  end
536
+ end
493
537
 
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
- )
538
+ def wire_block_stop(stream, state)
539
+ return unless stream.respond_to?(:on_content_block_stop_event)
540
+
541
+ stream.on_content_block_stop_event do |_event|
542
+ next unless state[:current_tool_use]
543
+
544
+ state[:tool_use_blocks] << state[:current_tool_use]
545
+ state[:current_tool_use] = nil
546
+ end
547
+ end
548
+
549
+ def wire_message_stop(stream, state)
550
+ return unless stream.respond_to?(:on_message_stop_event)
551
+
552
+ stream.on_message_stop_event do |event|
553
+ state[:stop_reason] = value(event, :stop_reason)
554
+ end
555
+ end
556
+
557
+ def build_stream_tool_calls(tool_use_blocks)
558
+ return nil if tool_use_blocks.empty?
559
+
560
+ tool_use_blocks.to_h do |block|
561
+ input = begin
562
+ Legion::JSON.load(block[:input_json])
563
+ rescue StandardError
564
+ {}
565
+ end
566
+ name = block[:name]
567
+ id = block[:tool_use_id] || name
568
+ [id, Legion::Extensions::Llm::ToolCall.new(id: id, name: name, arguments: input)]
569
+ end
501
570
  end
502
571
 
503
572
  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.9'
8
8
  end
9
9
  end
10
10
  end
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.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - LegionIO