amazon-bedrock-haystack 3.9.0__py3-none-any.whl → 3.10.0__py3-none-any.whl
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.
- {amazon_bedrock_haystack-3.9.0.dist-info → amazon_bedrock_haystack-3.10.0.dist-info}/METADATA +1 -1
- {amazon_bedrock_haystack-3.9.0.dist-info → amazon_bedrock_haystack-3.10.0.dist-info}/RECORD +5 -5
- haystack_integrations/components/generators/amazon_bedrock/chat/utils.py +121 -3
- {amazon_bedrock_haystack-3.9.0.dist-info → amazon_bedrock_haystack-3.10.0.dist-info}/WHEEL +0 -0
- {amazon_bedrock_haystack-3.9.0.dist-info → amazon_bedrock_haystack-3.10.0.dist-info}/licenses/LICENSE.txt +0 -0
{amazon_bedrock_haystack-3.9.0.dist-info → amazon_bedrock_haystack-3.10.0.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: amazon-bedrock-haystack
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.10.0
|
|
4
4
|
Summary: An integration of Amazon Bedrock as an AmazonBedrockGenerator component.
|
|
5
5
|
Project-URL: Documentation, https://github.com/deepset-ai/haystack-core-integrations/tree/main/integrations/amazon_bedrock#readme
|
|
6
6
|
Project-URL: Issues, https://github.com/deepset-ai/haystack-core-integrations/issues
|
|
@@ -12,11 +12,11 @@ haystack_integrations/components/generators/amazon_bedrock/adapters.py,sha256=yB
|
|
|
12
12
|
haystack_integrations/components/generators/amazon_bedrock/generator.py,sha256=c_saV5zxFYQVJT0Hzo80lKty46itL0Dp31VuDueYa3M,14716
|
|
13
13
|
haystack_integrations/components/generators/amazon_bedrock/chat/__init__.py,sha256=6GZ8Y3Lw0rLOsOAqi6Tu5mZC977UzQvgDxKpOWr8IQw,110
|
|
14
14
|
haystack_integrations/components/generators/amazon_bedrock/chat/chat_generator.py,sha256=iIaMsOOX9eYvR1GNgpxNKxaOli91ShrCv3MuBBK1NSs,24743
|
|
15
|
-
haystack_integrations/components/generators/amazon_bedrock/chat/utils.py,sha256=
|
|
15
|
+
haystack_integrations/components/generators/amazon_bedrock/chat/utils.py,sha256=g2SZV8LdLobaCZpwWCreBJn1BtS1V3-wQkpisStJrcY,29015
|
|
16
16
|
haystack_integrations/components/rankers/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
17
|
haystack_integrations/components/rankers/amazon_bedrock/__init__.py,sha256=Zrc3BSVkEaXYpliEi6hKG9bqW4J7DNk93p50SuoyT1Q,107
|
|
18
18
|
haystack_integrations/components/rankers/amazon_bedrock/ranker.py,sha256=enAjf2QyDwfpidKkFCdLz954cx-Tjh9emrOS3vINJDg,12344
|
|
19
|
-
amazon_bedrock_haystack-3.
|
|
20
|
-
amazon_bedrock_haystack-3.
|
|
21
|
-
amazon_bedrock_haystack-3.
|
|
22
|
-
amazon_bedrock_haystack-3.
|
|
19
|
+
amazon_bedrock_haystack-3.10.0.dist-info/METADATA,sha256=DZDchQY_Nsi4GsU4fZKTVkHxFcnn4cYuXNMjZ1VxlQg,2288
|
|
20
|
+
amazon_bedrock_haystack-3.10.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
21
|
+
amazon_bedrock_haystack-3.10.0.dist-info/licenses/LICENSE.txt,sha256=B05uMshqTA74s-0ltyHKI6yoPfJ3zYgQbvcXfDVGFf8,10280
|
|
22
|
+
amazon_bedrock_haystack-3.10.0.dist-info/RECORD,,
|
|
@@ -55,6 +55,11 @@ def _format_tool_call_message(tool_call_message: ChatMessage) -> Dict[str, Any]:
|
|
|
55
55
|
Dictionary representing the tool call message in Bedrock's expected format
|
|
56
56
|
"""
|
|
57
57
|
content: List[Dict[str, Any]] = []
|
|
58
|
+
|
|
59
|
+
# tool call messages can contain reasoning content
|
|
60
|
+
if reasoning_contents := tool_call_message.meta.get("reasoning_contents"):
|
|
61
|
+
content.extend(_format_reasoning_contents(reasoning_contents=reasoning_contents))
|
|
62
|
+
|
|
58
63
|
# Tool call message can contain text
|
|
59
64
|
if tool_call_message.text:
|
|
60
65
|
content.append({"text": tool_call_message.text})
|
|
@@ -157,6 +162,24 @@ def _repair_tool_result_messages(bedrock_formatted_messages: List[Dict[str, Any]
|
|
|
157
162
|
return [msg for _, msg in repaired_bedrock_formatted_messages]
|
|
158
163
|
|
|
159
164
|
|
|
165
|
+
def _format_reasoning_contents(reasoning_contents: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
|
|
166
|
+
"""
|
|
167
|
+
Format reasoning contents to match Bedrock's expected structure.
|
|
168
|
+
|
|
169
|
+
:param reasoning_contents: List of reasoning content dictionaries from Haystack ChatMessage metadata.
|
|
170
|
+
:returns: List of formatted reasoning content dictionaries for Bedrock.
|
|
171
|
+
"""
|
|
172
|
+
formatted_contents = []
|
|
173
|
+
for reasoning_content in reasoning_contents:
|
|
174
|
+
formatted_content = {"reasoningContent": reasoning_content["reasoning_content"]}
|
|
175
|
+
if reasoning_text := formatted_content["reasoningContent"].pop("reasoning_text", None):
|
|
176
|
+
formatted_content["reasoningContent"]["reasoningText"] = reasoning_text
|
|
177
|
+
if redacted_content := formatted_content["reasoningContent"].pop("redacted_content", None):
|
|
178
|
+
formatted_content["reasoningContent"]["redactedContent"] = redacted_content
|
|
179
|
+
formatted_contents.append(formatted_content)
|
|
180
|
+
return formatted_contents
|
|
181
|
+
|
|
182
|
+
|
|
160
183
|
def _format_text_image_message(message: ChatMessage) -> Dict[str, Any]:
|
|
161
184
|
"""
|
|
162
185
|
Format a Haystack ChatMessage containing text and optional image content into Bedrock format.
|
|
@@ -168,6 +191,10 @@ def _format_text_image_message(message: ChatMessage) -> Dict[str, Any]:
|
|
|
168
191
|
content_parts = message._content
|
|
169
192
|
|
|
170
193
|
bedrock_content_blocks: List[Dict[str, Any]] = []
|
|
194
|
+
# Add reasoning content if available as the first content block
|
|
195
|
+
if message.meta.get("reasoning_contents"):
|
|
196
|
+
bedrock_content_blocks.extend(_format_reasoning_contents(reasoning_contents=message.meta["reasoning_contents"]))
|
|
197
|
+
|
|
171
198
|
for part in content_parts:
|
|
172
199
|
if isinstance(part, TextContent):
|
|
173
200
|
bedrock_content_blocks.append({"text": part.text})
|
|
@@ -221,7 +248,6 @@ def _format_messages(messages: List[ChatMessage]) -> Tuple[List[Dict[str, Any]],
|
|
|
221
248
|
return system_prompts, repaired_bedrock_formatted_messages
|
|
222
249
|
|
|
223
250
|
|
|
224
|
-
# Bedrock to Haystack util method
|
|
225
251
|
def _parse_completion_response(response_body: Dict[str, Any], model: str) -> List[ChatMessage]:
|
|
226
252
|
"""
|
|
227
253
|
Parse a Bedrock API response into Haystack ChatMessage objects.
|
|
@@ -255,6 +281,7 @@ def _parse_completion_response(response_body: Dict[str, Any], model: str) -> Lis
|
|
|
255
281
|
# Process all content blocks and combine them into a single message
|
|
256
282
|
text_content = []
|
|
257
283
|
tool_calls = []
|
|
284
|
+
reasoning_contents = []
|
|
258
285
|
for content_block in content_blocks:
|
|
259
286
|
if "text" in content_block:
|
|
260
287
|
text_content.append(content_block["text"])
|
|
@@ -267,6 +294,17 @@ def _parse_completion_response(response_body: Dict[str, Any], model: str) -> Lis
|
|
|
267
294
|
arguments=tool_use.get("input", {}),
|
|
268
295
|
)
|
|
269
296
|
tool_calls.append(tool_call)
|
|
297
|
+
elif "reasoningContent" in content_block:
|
|
298
|
+
reasoning_content = content_block["reasoningContent"]
|
|
299
|
+
# If reasoningText is present, replace it with reasoning_text
|
|
300
|
+
if "reasoningText" in reasoning_content:
|
|
301
|
+
reasoning_content["reasoning_text"] = reasoning_content.pop("reasoningText")
|
|
302
|
+
if "redactedContent" in reasoning_content:
|
|
303
|
+
reasoning_content["redacted_content"] = reasoning_content.pop("redactedContent")
|
|
304
|
+
reasoning_contents.append({"reasoning_content": reasoning_content})
|
|
305
|
+
|
|
306
|
+
# If reasoning contents were found, add them to the base meta
|
|
307
|
+
base_meta.update({"reasoning_contents": reasoning_contents})
|
|
270
308
|
|
|
271
309
|
# Create a single ChatMessage with combined text and tool calls
|
|
272
310
|
replies.append(ChatMessage.from_assistant(" ".join(text_content), tool_calls=tool_calls, meta=base_meta))
|
|
@@ -274,7 +312,6 @@ def _parse_completion_response(response_body: Dict[str, Any], model: str) -> Lis
|
|
|
274
312
|
return replies
|
|
275
313
|
|
|
276
314
|
|
|
277
|
-
# Bedrock streaming to Haystack util methods
|
|
278
315
|
def _convert_event_to_streaming_chunk(
|
|
279
316
|
event: Dict[str, Any], model: str, component_info: ComponentInfo
|
|
280
317
|
) -> StreamingChunk:
|
|
@@ -367,6 +404,22 @@ def _convert_event_to_streaming_chunk(
|
|
|
367
404
|
"received_at": datetime.now(timezone.utc).isoformat(),
|
|
368
405
|
},
|
|
369
406
|
)
|
|
407
|
+
# This is for accumulating reasoning content deltas
|
|
408
|
+
elif "reasoningContent" in delta:
|
|
409
|
+
reasoning_content = delta["reasoningContent"]
|
|
410
|
+
if "redactedContent" in reasoning_content:
|
|
411
|
+
reasoning_content["redacted_content"] = reasoning_content.pop("redactedContent")
|
|
412
|
+
streaming_chunk = StreamingChunk(
|
|
413
|
+
content="",
|
|
414
|
+
meta={
|
|
415
|
+
"model": model,
|
|
416
|
+
"index": 0,
|
|
417
|
+
"tool_calls": None,
|
|
418
|
+
"finish_reason": None,
|
|
419
|
+
"received_at": datetime.now(timezone.utc).isoformat(),
|
|
420
|
+
"reasoning_contents": [{"index": block_idx, "reasoning_content": reasoning_content}],
|
|
421
|
+
},
|
|
422
|
+
)
|
|
370
423
|
|
|
371
424
|
elif "messageStop" in event:
|
|
372
425
|
finish_reason = event["messageStop"].get("stopReason")
|
|
@@ -406,6 +459,66 @@ def _convert_event_to_streaming_chunk(
|
|
|
406
459
|
return streaming_chunk
|
|
407
460
|
|
|
408
461
|
|
|
462
|
+
def _process_reasoning_contents(chunks: List[StreamingChunk]) -> List[Dict[str, Any]]:
|
|
463
|
+
"""
|
|
464
|
+
Process reasoning contents from a list of StreamingChunk objects into the Bedrock expected format.
|
|
465
|
+
|
|
466
|
+
:param chunks: List of StreamingChunk objects potentially containing reasoning contents.
|
|
467
|
+
|
|
468
|
+
:returns: List of Bedrock formatted reasoning content dictionaries
|
|
469
|
+
"""
|
|
470
|
+
formatted_reasoning_contents = []
|
|
471
|
+
current_index = None
|
|
472
|
+
reasoning_text = ""
|
|
473
|
+
reasoning_signature = None
|
|
474
|
+
redacted_content = None
|
|
475
|
+
for chunk in chunks:
|
|
476
|
+
reasoning_contents = chunk.meta.get("reasoning_contents", [])
|
|
477
|
+
|
|
478
|
+
for reasoning_content in reasoning_contents:
|
|
479
|
+
content_block_index = reasoning_content["index"]
|
|
480
|
+
|
|
481
|
+
# Start new group when index changes
|
|
482
|
+
if current_index is not None and content_block_index != current_index:
|
|
483
|
+
# Finalize current group
|
|
484
|
+
if reasoning_text:
|
|
485
|
+
formatted_reasoning_contents.append(
|
|
486
|
+
{
|
|
487
|
+
"reasoning_content": {
|
|
488
|
+
"reasoning_text": {"text": reasoning_text, "signature": reasoning_signature},
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
)
|
|
492
|
+
if redacted_content:
|
|
493
|
+
formatted_reasoning_contents.append({"reasoning_content": {"redacted_content": redacted_content}})
|
|
494
|
+
reasoning_text = ""
|
|
495
|
+
reasoning_signature = None
|
|
496
|
+
redacted_content = None
|
|
497
|
+
|
|
498
|
+
# Accumulate content for current index
|
|
499
|
+
current_index = content_block_index
|
|
500
|
+
reasoning_text += reasoning_content["reasoning_content"].get("text", "")
|
|
501
|
+
if "redacted_content" in reasoning_content["reasoning_content"]:
|
|
502
|
+
redacted_content = reasoning_content["reasoning_content"]["redacted_content"]
|
|
503
|
+
if "signature" in reasoning_content["reasoning_content"]:
|
|
504
|
+
reasoning_signature = reasoning_content["reasoning_content"]["signature"]
|
|
505
|
+
|
|
506
|
+
# Finalize the last group
|
|
507
|
+
if current_index is not None:
|
|
508
|
+
if reasoning_text:
|
|
509
|
+
formatted_reasoning_contents.append(
|
|
510
|
+
{
|
|
511
|
+
"reasoning_content": {
|
|
512
|
+
"reasoning_text": {"text": reasoning_text, "signature": reasoning_signature},
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
)
|
|
516
|
+
if redacted_content:
|
|
517
|
+
formatted_reasoning_contents.append({"reasoning_content": {"redacted_content": redacted_content}})
|
|
518
|
+
|
|
519
|
+
return formatted_reasoning_contents
|
|
520
|
+
|
|
521
|
+
|
|
409
522
|
def _convert_streaming_chunks_to_chat_message(chunks: List[StreamingChunk]) -> ChatMessage:
|
|
410
523
|
"""
|
|
411
524
|
Converts a list of streaming chunks into a ChatMessage object.
|
|
@@ -421,8 +534,12 @@ def _convert_streaming_chunks_to_chat_message(chunks: List[StreamingChunk]) -> C
|
|
|
421
534
|
A ChatMessage object constructed from the streaming chunks, containing the aggregated text, processed tool
|
|
422
535
|
calls, and metadata.
|
|
423
536
|
"""
|
|
537
|
+
# Join all text content from the chunks
|
|
424
538
|
text = "".join([chunk.content for chunk in chunks])
|
|
425
539
|
|
|
540
|
+
# If reasoning content is present in any chunk, accumulate it
|
|
541
|
+
reasoning_contents = _process_reasoning_contents(chunks=chunks)
|
|
542
|
+
|
|
426
543
|
# Process tool calls if present in any chunk
|
|
427
544
|
tool_calls = []
|
|
428
545
|
tool_call_data: Dict[int, Dict[str, str]] = {} # Track tool calls by index
|
|
@@ -447,7 +564,7 @@ def _convert_streaming_chunks_to_chat_message(chunks: List[StreamingChunk]) -> C
|
|
|
447
564
|
# Convert accumulated tool call data into ToolCall objects
|
|
448
565
|
for call_data in tool_call_data.values():
|
|
449
566
|
try:
|
|
450
|
-
arguments = json.loads(call_data
|
|
567
|
+
arguments = json.loads(call_data.get("arguments", "{}")) if call_data.get("arguments") else {}
|
|
451
568
|
tool_calls.append(ToolCall(id=call_data["id"], tool_name=call_data["name"], arguments=arguments))
|
|
452
569
|
except json.JSONDecodeError:
|
|
453
570
|
logger.warning(
|
|
@@ -474,6 +591,7 @@ def _convert_streaming_chunks_to_chat_message(chunks: List[StreamingChunk]) -> C
|
|
|
474
591
|
"finish_reason": finish_reason,
|
|
475
592
|
"completion_start_time": chunks[0].meta.get("received_at"), # first chunk received
|
|
476
593
|
"usage": usage,
|
|
594
|
+
"reasoning_contents": reasoning_contents,
|
|
477
595
|
}
|
|
478
596
|
|
|
479
597
|
return ChatMessage.from_assistant(text=text or None, tool_calls=tool_calls, meta=meta)
|
|
File without changes
|
|
File without changes
|