Skip to content

Commit 3e0632c

Browse files
authored
opentelemetry-instrumentation-botocore: fix handling of tool input chunked json in bedrock converse_stream (#3544)
* opentelemetry-instrumentation-botocore: fix handling of tool input chunked json in converse_stream We need to accumulate all the tool input as string before decoding it otherwise we may end up with invalid json. * Add changelog * Remove leftover print * No need for too-many-statements disable
1 parent 7bd0895 commit 3e0632c

File tree

5 files changed

+622
-6
lines changed

5 files changed

+622
-6
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3737
([#3520](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3520))
3838
- `opentelemetry-instrumentation-botocore` Ensure spans end on early stream closure for Bedrock Streaming APIs
3939
([#3481](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3481))
40+
- `opentelemetry-instrumentation-botocore`: fix handling of tool input in Bedrock ConverseStream
41+
([#3544](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3544))
4042
- `opentelemetry-instrumentation-botocore` Add type check when extracting tool use from Bedrock request message content
4143
([#3548](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3548))
4244

instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/bedrock_utils.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ def __init__(
6464
self._response = {}
6565
self._message = None
6666
self._content_block = {}
67+
self._tool_json_input_buf = ""
6768
self._record_message = False
6869
self._ended = False
6970

@@ -89,28 +90,40 @@ def _process_event(self, event):
8990
# {'contentBlockStart': {'start': {'toolUse': {'toolUseId': 'id', 'name': 'func_name'}}, 'contentBlockIndex': 1}}
9091
start = event["contentBlockStart"].get("start", {})
9192
if "toolUse" in start:
92-
tool_use = _decode_tool_use(start["toolUse"])
93-
self._content_block = {"toolUse": tool_use}
93+
self._content_block = {"toolUse": start["toolUse"]}
9494
return
9595

9696
if "contentBlockDelta" in event:
9797
# {'contentBlockDelta': {'delta': {'text': "Hello"}, 'contentBlockIndex': 0}}
9898
# {'contentBlockDelta': {'delta': {'toolUse': {'input': '{"location":"Seattle"}'}}, 'contentBlockIndex': 1}}
99+
# {'contentBlockDelta': {'delta': {'toolUse': {'input': 'a", "Yok'}}, 'contentBlockIndex': 1}}
99100
if self._record_message:
100101
delta = event["contentBlockDelta"].get("delta", {})
101102
if "text" in delta:
102103
self._content_block.setdefault("text", "")
103104
self._content_block["text"] += delta["text"]
104105
elif "toolUse" in delta:
105-
tool_use = _decode_tool_use(delta["toolUse"])
106-
self._content_block["toolUse"].update(tool_use)
106+
if (
107+
input_buf := delta["toolUse"].get("input")
108+
) is not None:
109+
self._tool_json_input_buf += input_buf
107110
return
108111

109112
if "contentBlockStop" in event:
110113
# {'contentBlockStop': {'contentBlockIndex': 0}}
111114
if self._record_message:
115+
if self._tool_json_input_buf:
116+
try:
117+
self._content_block["toolUse"]["input"] = json.loads(
118+
self._tool_json_input_buf
119+
)
120+
except json.DecodeError:
121+
self._content_block["toolUse"]["input"] = (
122+
self._tool_json_input_buf
123+
)
112124
self._message["content"].append(self._content_block)
113125
self._content_block = {}
126+
self._tool_json_input_buf = ""
114127
return
115128

116129
if "messageStop" in event:

instrumentation/opentelemetry-instrumentation-botocore/tests/bedrock_utils.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -275,8 +275,6 @@ def remove_none_values(body):
275275
continue
276276
if isinstance(value, dict):
277277
result[key] = remove_none_values(value)
278-
elif isinstance(value, list):
279-
result[key] = [remove_none_values(i) for i in value]
280278
else:
281279
result[key] = value
282280
return result

0 commit comments

Comments
 (0)