From 1bec9f3e97c5d81ffa3a7d6a486d05c43fde4c37 Mon Sep 17 00:00:00 2001 From: abhiramshaji-cyber Date: Tue, 27 Oct 2026 12:17:08 -0400 Subject: [PATCH] fix(memory): encode bytes in OpenAI converter reasoning blocks OpenAIConverseConverter stored reasoningContent blocks as is, so a redactedContent value (bytes) made json.dumps raise and broke the agent call. Encode bytes the same way SessionMessage.to_dict does when saving, and decode them on restore, matching AgentCoreMemoryConverter. Fixes #680 --- .../integrations/strands/converters/openai.py | 6 ++--- .../strands/test_openai_converter.py | 22 +++++++++++++++++++ 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/bedrock_agentcore/memory/integrations/strands/converters/openai.py b/src/bedrock_agentcore/memory/integrations/strands/converters/openai.py index e5acfc4f..fbbee11e 100644 --- a/src/bedrock_agentcore/memory/integrations/strands/converters/openai.py +++ b/src/bedrock_agentcore/memory/integrations/strands/converters/openai.py @@ -8,7 +8,7 @@ import logging from typing import Any, Tuple -from strands.types.session import SessionMessage +from strands.types.session import SessionMessage, decode_bytes_values, encode_bytes_values from .protocol import exceeds_conversational_limit @@ -45,7 +45,7 @@ def _bedrock_to_openai(message: dict) -> dict: elif "reasoningContent" in item: # OpenAI message shape does not have a stable multi-turn reasoning block field. # Preserve original block(s) in storage-only extension field for lossless restore. - reasoning_blocks.append(item) + reasoning_blocks.append(encode_bytes_values(item)) elif "toolUse" in item: tu = item["toolUse"] tool_calls.append( @@ -120,7 +120,7 @@ def _openai_to_bedrock(openai_msg: dict) -> dict: for rc in openai_msg.get("_strands_reasoning_content", []): if isinstance(rc, dict) and "reasoningContent" in rc: - reasoning_items.append(rc) + reasoning_items.append(decode_bytes_values(rc)) bedrock_role = "assistant" if role == "assistant" else "user" diff --git a/tests/bedrock_agentcore/memory/integrations/strands/test_openai_converter.py b/tests/bedrock_agentcore/memory/integrations/strands/test_openai_converter.py index 7b94db92..3b74edf3 100644 --- a/tests/bedrock_agentcore/memory/integrations/strands/test_openai_converter.py +++ b/tests/bedrock_agentcore/memory/integrations/strands/test_openai_converter.py @@ -90,6 +90,28 @@ def test_reasoning_content_round_trips_in_openai_converter(): assert any("reasoningContent" in block for block in restored_content) +def test_redacted_reasoning_bytes_round_trip_in_openai_converter(): + msg = SessionMessage( + message={ + "role": "assistant", + "content": [ + {"reasoningContent": {"redactedContent": b"rsn_abc"}}, + {"text": "208"}, + ], + }, + message_id=8, + ) + + payload_json, _ = OpenAIConverseConverter.message_to_payload(msg)[0] + events = [{"payload": [{"conversational": {"content": {"text": payload_json}}}]}] + restored = OpenAIConverseConverter.events_to_messages(events) + + assert restored[0].message["content"] == [ + {"reasoningContent": {"redactedContent": b"rsn_abc"}}, + {"text": "208"}, + ] + + def test_openai_converter_round_trips_from_blob_payload(): msg = SessionMessage( message={