botocore: add basic tracing for Bedrock InvokeModelWithStreamResponse (#3206)

* Add basic tracing for InvokeModelWithResponseStream

* Add changelog and please pylint
This commit is contained in:
Riccardo Magliocchetti
2025-01-28 09:55:28 +01:00
committed by GitHub
parent 5478a0b77a
commit 93e6fcfa26
11 changed files with 720 additions and 9 deletions

View File

@ -47,6 +47,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
([#3200](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3200))
- `opentelemetry-opentelemetry-botocore` Add basic support for GenAI attributes for AWS Bedrock ConverseStream API
([#3204](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3204))
- `opentelemetry-opentelemetry-botocore` Add basic support for GenAI attributes for AWS Bedrock InvokeModelWithStreamResponse API
([#3206](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3206))
- `opentelemetry-instrumentation-pymssql` Add pymssql instrumentation
([#394](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/394))

View File

@ -20,6 +20,7 @@ Available examples
- `converse.py` uses `bedrock-runtime` `Converse API <https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_Converse.html>_`.
- `converse_stream.py` uses `bedrock-runtime` `ConverseStream API <https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_ConverseStream.html>_`.
- `invoke_model.py` uses `bedrock-runtime` `InvokeModel API <https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_InvokeModel.html>_`.
- `invoke_model_stream.py` uses `bedrock-runtime` `InvokeModelWithResponseStrea API <https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_InvokeModelWithResponseStream.html>_`.
Setup
-----

View File

@ -0,0 +1,51 @@
import json
import os
import boto3
def main():
chat_model = os.getenv("CHAT_MODEL", "amazon.titan-text-lite-v1")
prompt = "Write a short poem on OpenTelemetry."
if "amazon.titan" in chat_model:
body = {
"inputText": prompt,
"textGenerationConfig": {},
}
elif "amazon.nova" in chat_model:
body = {
"messages": [{"role": "user", "content": [{"text": prompt}]}],
"schemaVersion": "messages-v1",
}
elif "anthropic.claude" in chat_model:
body = {
"messages": [
{"role": "user", "content": [{"text": prompt, "type": "text"}]}
],
"anthropic_version": "bedrock-2023-05-31",
"max_tokens": 200,
}
else:
raise ValueError()
client = boto3.client("bedrock-runtime")
response = client.invoke_model_with_response_stream(
modelId=chat_model,
body=json.dumps(body),
)
answer = ""
for event in response["body"]:
json_bytes = event.get("chunk", {}).get("bytes", b"")
decoded = json_bytes.decode("utf-8")
chunk = json.loads(decoded)
if "outputText" in chunk:
answer += chunk["outputText"]
elif "completion" in chunk:
answer += chunk["completion"]
elif "contentBlockDelta" in chunk:
answer += chunk["contentBlockDelta"]["delta"]["text"]
print(answer)
if __name__ == "__main__":
main()

View File

@ -28,6 +28,7 @@ from botocore.response import StreamingBody
from opentelemetry.instrumentation.botocore.extensions.bedrock_utils import (
ConverseStreamWrapper,
InvokeModelWithResponseStreamWrapper,
)
from opentelemetry.instrumentation.botocore.extensions.types import (
_AttributeMapT,
@ -66,8 +67,16 @@ class _BedrockRuntimeExtension(_AwsSdkExtension):
Amazon Bedrock Runtime</a>.
"""
_HANDLED_OPERATIONS = {"Converse", "ConverseStream", "InvokeModel"}
_DONT_CLOSE_SPAN_ON_END_OPERATIONS = {"ConverseStream"}
_HANDLED_OPERATIONS = {
"Converse",
"ConverseStream",
"InvokeModel",
"InvokeModelWithResponseStream",
}
_DONT_CLOSE_SPAN_ON_END_OPERATIONS = {
"ConverseStream",
"InvokeModelWithResponseStream",
}
def should_end_span_on_exit(self):
return (
@ -288,6 +297,20 @@ class _BedrockRuntimeExtension(_AwsSdkExtension):
# InvokeModel
if "body" in result and isinstance(result["body"], StreamingBody):
self._invoke_model_on_success(span, result, model_id)
return
# InvokeModelWithResponseStream
if "body" in result and isinstance(result["body"], EventStream):
def invoke_model_stream_done_callback(response):
# the callback gets data formatted as the simpler converse API
self._converse_on_success(span, response)
span.end()
result["body"] = InvokeModelWithResponseStreamWrapper(
result["body"], invoke_model_stream_done_callback, model_id
)
return
# pylint: disable=no-self-use
def _handle_amazon_titan_response(

View File

@ -18,6 +18,8 @@
from __future__ import annotations
import json
from botocore.eventstream import EventStream
from wrapt import ObjectProxy
@ -46,20 +48,21 @@ class ConverseStreamWrapper(ObjectProxy):
def _process_event(self, event):
if "messageStart" in event:
# {'messageStart': {'role': 'assistant'}}
pass
return
if "contentBlockDelta" in event:
# {'contentBlockDelta': {'delta': {'text': "Hello"}, 'contentBlockIndex': 0}}
pass
return
if "contentBlockStop" in event:
# {'contentBlockStop': {'contentBlockIndex': 0}}
pass
return
if "messageStop" in event:
# {'messageStop': {'stopReason': 'end_turn'}}
if stop_reason := event["messageStop"].get("stopReason"):
self._response["stopReason"] = stop_reason
return
if "metadata" in event:
# {'metadata': {'usage': {'inputTokens': 12, 'outputTokens': 15, 'totalTokens': 27}, 'metrics': {'latencyMs': 2980}}}
@ -72,3 +75,136 @@ class ConverseStreamWrapper(ObjectProxy):
self._response["usage"]["outputTokens"] = output_tokens
self._stream_done_callback(self._response)
return
# pylint: disable=abstract-method
class InvokeModelWithResponseStreamWrapper(ObjectProxy):
"""Wrapper for botocore.eventstream.EventStream"""
def __init__(
self,
stream: EventStream,
stream_done_callback,
model_id: str,
):
super().__init__(stream)
self._stream_done_callback = stream_done_callback
self._model_id = model_id
# accumulating things in the same shape of the Converse API
# {"usage": {"inputTokens": 0, "outputTokens": 0}, "stopReason": "finish"}
self._response = {}
def __iter__(self):
for event in self.__wrapped__:
self._process_event(event)
yield event
def _process_event(self, event):
if "chunk" not in event:
return
json_bytes = event["chunk"].get("bytes", b"")
decoded = json_bytes.decode("utf-8")
try:
chunk = json.loads(decoded)
except json.JSONDecodeError:
return
if "amazon.titan" in self._model_id:
self._process_amazon_titan_chunk(chunk)
elif "amazon.nova" in self._model_id:
self._process_amazon_nova_chunk(chunk)
elif "anthropic.claude" in self._model_id:
self._process_anthropic_claude_chunk(chunk)
def _process_invocation_metrics(self, invocation_metrics):
self._response["usage"] = {}
if input_tokens := invocation_metrics.get("inputTokenCount"):
self._response["usage"]["inputTokens"] = input_tokens
if output_tokens := invocation_metrics.get("outputTokenCount"):
self._response["usage"]["outputTokens"] = output_tokens
def _process_amazon_titan_chunk(self, chunk):
if (stop_reason := chunk.get("completionReason")) is not None:
self._response["stopReason"] = stop_reason
if invocation_metrics := chunk.get("amazon-bedrock-invocationMetrics"):
# "amazon-bedrock-invocationMetrics":{
# "inputTokenCount":9,"outputTokenCount":128,"invocationLatency":3569,"firstByteLatency":2180
# }
self._process_invocation_metrics(invocation_metrics)
self._stream_done_callback(self._response)
def _process_amazon_nova_chunk(self, chunk):
if "messageStart" in chunk:
# {'messageStart': {'role': 'assistant'}}
return
if "contentBlockDelta" in chunk:
# {'contentBlockDelta': {'delta': {'text': "Hello"}, 'contentBlockIndex': 0}}
return
if "contentBlockStop" in chunk:
# {'contentBlockStop': {'contentBlockIndex': 0}}
return
if "messageStop" in chunk:
# {'messageStop': {'stopReason': 'end_turn'}}
if stop_reason := chunk["messageStop"].get("stopReason"):
self._response["stopReason"] = stop_reason
return
if "metadata" in chunk:
# {'metadata': {'usage': {'inputTokens': 8, 'outputTokens': 117}, 'metrics': {}, 'trace': {}}}
if usage := chunk["metadata"].get("usage"):
self._response["usage"] = {}
if input_tokens := usage.get("inputTokens"):
self._response["usage"]["inputTokens"] = input_tokens
if output_tokens := usage.get("outputTokens"):
self._response["usage"]["outputTokens"] = output_tokens
self._stream_done_callback(self._response)
return
def _process_anthropic_claude_chunk(self, chunk):
# pylint: disable=too-many-return-statements
if not (message_type := chunk.get("type")):
return
if message_type == "message_start":
# {'type': 'message_start', 'message': {'id': 'id', 'type': 'message', 'role': 'assistant', 'model': 'claude-2.0', 'content': [], 'stop_reason': None, 'stop_sequence': None, 'usage': {'input_tokens': 18, 'output_tokens': 1}}}
return
if message_type == "content_block_start":
# {'type': 'content_block_start', 'index': 0, 'content_block': {'type': 'text', 'text': ''}}
return
if message_type == "content_block_delta":
# {'type': 'content_block_delta', 'index': 0, 'delta': {'type': 'text_delta', 'text': 'Here'}}
return
if message_type == "content_block_stop":
# {'type': 'content_block_stop', 'index': 0}
return
if message_type == "message_delta":
# {'type': 'message_delta', 'delta': {'stop_reason': 'end_turn', 'stop_sequence': None}, 'usage': {'output_tokens': 123}}
if (
stop_reason := chunk.get("delta", {}).get("stop_reason")
) is not None:
self._response["stopReason"] = stop_reason
return
if message_type == "message_stop":
# {'type': 'message_stop', 'amazon-bedrock-invocationMetrics': {'inputTokenCount': 18, 'outputTokenCount': 123, 'invocationLatency': 5250, 'firstByteLatency': 290}}
if invocation_metrics := chunk.get(
"amazon-bedrock-invocationMetrics"
):
self._process_invocation_metrics(invocation_metrics)
self._stream_done_callback(self._response)
return

View File

@ -128,7 +128,7 @@ def assert_converse_completion_attributes(
)
def assert_converse_stream_completion_attributes(
def assert_stream_completion_attributes(
span: ReadableSpan,
request_model: str,
input_tokens: int | None = None,

View File

@ -0,0 +1,51 @@
interactions:
- request:
body: null
headers:
Content-Length:
- '0'
User-Agent:
- !!binary |
Qm90bzMvMS4zNS41NiBtZC9Cb3RvY29yZSMxLjM1LjU2IHVhLzIuMCBvcy9saW51eCM2LjEuMC0x
MDM0LW9lbSBtZC9hcmNoI3g4Nl82NCBsYW5nL3B5dGhvbiMzLjEwLjEyIG1kL3B5aW1wbCNDUHl0
aG9uIGNmZy9yZXRyeS1tb2RlI2xlZ2FjeSBCb3RvY29yZS8xLjM1LjU2
X-Amz-Date:
- !!binary |
MjAyNTAxMjRUMTM0NDM5Wg==
X-Amz-Security-Token:
- test_aws_security_token
X-Amzn-Trace-Id:
- !!binary |
Um9vdD0xLTFlMjljM2Y1LTU2MzZhOWI4MmViYTYxOTFiOTcwOTI2YTtQYXJlbnQ9NzA1NzBlZjUy
YzJkZjliYjtTYW1wbGVkPTE=
amz-sdk-invocation-id:
- !!binary |
ZDg2MjFlMzAtNTk3Yi00ZWM3LWJlNGEtMThkMDQwZTRhMzcw
amz-sdk-request:
- !!binary |
YXR0ZW1wdD0x
authorization:
- Bearer test_aws_authorization
method: POST
uri: https://bedrock-runtime.us-east-1.amazonaws.com/model/does-not-exist/invoke-with-response-stream
response:
body:
string: '{"message":"The provided model identifier is invalid."}'
headers:
Connection:
- keep-alive
Content-Length:
- '55'
Content-Type:
- application/json
Date:
- Fri, 24 Jan 2025 13:44:40 GMT
Set-Cookie: test_set_cookie
x-amzn-ErrorType:
- ValidationException:http://internal.amazon.com/coral/com.amazon.bedrock/
x-amzn-RequestId:
- 6460a108-875d-4e26-bcdf-f03c4c815f74
status:
code: 400
message: Bad Request
version: 1

View File

@ -0,0 +1,144 @@
interactions:
- request:
body: '{"messages": [{"role": "user", "content": [{"text": "Say this is a test"}]}],
"inferenceConfig": {"max_new_tokens": 10, "temperature": 0.8, "topP": 1, "stopSequences":
["|"]}, "schemaVersion": "messages-v1"}'
headers:
Content-Length:
- '207'
User-Agent:
- !!binary |
Qm90bzMvMS4zNS41NiBtZC9Cb3RvY29yZSMxLjM1LjU2IHVhLzIuMCBvcy9saW51eCM2LjEuMC0x
MDM0LW9lbSBtZC9hcmNoI3g4Nl82NCBsYW5nL3B5dGhvbiMzLjEwLjEyIG1kL3B5aW1wbCNDUHl0
aG9uIGNmZy9yZXRyeS1tb2RlI2xlZ2FjeSBCb3RvY29yZS8xLjM1LjU2
X-Amz-Date:
- !!binary |
MjAyNTAxMjRUMTM0NDM3Wg==
X-Amz-Security-Token:
- test_aws_security_token
X-Amzn-Trace-Id:
- !!binary |
Um9vdD0xLWE0YWY3ZjVkLTY5YmE5ZDNiNjg5YjM2OTRkYThmZDk5NDtQYXJlbnQ9OThiYjVhY2U3
MDE2YzZiZTtTYW1wbGVkPTE=
amz-sdk-invocation-id:
- !!binary |
MmZkNDA5NjQtYTBiNS00NzAwLTljYjUtNjI5MWQ2OWU3YTFm
amz-sdk-request:
- !!binary |
YXR0ZW1wdD0x
authorization:
- Bearer test_aws_authorization
method: POST
uri: https://bedrock-runtime.us-east-1.amazonaws.com/model/amazon.nova-micro-v1%3A0/invoke-with-response-stream
response:
body:
string: !!binary |
AAAA0QAAAEswuRGYCzpldmVudC10eXBlBwAFY2h1bmsNOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0
aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJieXRlcyI6ImV5SnRaWE56WVdkbFUzUmhj
blFpT25zaWNtOXNaU0k2SW1GemMybHpkR0Z1ZENKOWZRPT0iLCJwIjoiYWJjZGVmZ2hpamtsbW5v
cHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFUifVUlBC4AAADcAAAAS8gp1SkLOmV2ZW50
LXR5cGUHAAVjaHVuaw06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10
eXBlBwAFZXZlbnR7ImJ5dGVzIjoiZXlKamIyNTBaVzUwUW14dlkydEVaV3gwWVNJNmV5SmtaV3gw
WVNJNmV5SjBaWGgwSWpvaVNYUWlmU3dpWTI5dWRHVnVkRUpzYjJOclNXNWtaWGdpT2pCOWZRPT0i
LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyIn1vHubCAAAAywAAAEsa6Z67CzpldmVudC10eXBlBwAF
Y2h1bmsNOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2
ZW50eyJieXRlcyI6ImV5SmpiMjUwWlc1MFFteHZZMnRUZEc5d0lqcDdJbU52Ym5SbGJuUkNiRzlq
YTBsdVpHVjRJam93ZlgwPSIsInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkci
fTNzlqIAAADdAAAAS/VJ/JkLOmV2ZW50LXR5cGUHAAVjaHVuaw06Y29udGVudC10eXBlBwAQYXBw
bGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImJ5dGVzIjoiZXlKamIyNTBaVzUw
UW14dlkydEVaV3gwWVNJNmV5SmtaV3gwWVNJNmV5SjBaWGgwSWpvaUlITnZkVzVrY3lKOUxDSmpi
MjUwWlc1MFFteHZZMnRKYm1SbGVDSTZNWDE5IiwicCI6ImFiY2RlZmdoaWprbG1ubyJ9PeTnmAAA
AK8AAABLdltPNgs6ZXZlbnQtdHlwZQcABWNodW5rDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlv
bi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiYnl0ZXMiOiJleUpqYjI1MFpXNTBRbXh2WTJ0
VGRHOXdJanA3SW1OdmJuUmxiblJDYkc5amEwbHVaR1Y0SWpveGZYMD0iLCJwIjoiYWJjZGUifUde
LEMAAADzAAAAS4u4bfwLOmV2ZW50LXR5cGUHAAVjaHVuaw06Y29udGVudC10eXBlBwAQYXBwbGlj
YXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImJ5dGVzIjoiZXlKamIyNTBaVzUwUW14
dlkydEVaV3gwWVNJNmV5SmtaV3gwWVNJNmV5SjBaWGgwSWpvaUlHeHBhMlVpZlN3aVkyOXVkR1Z1
ZEVKc2IyTnJTVzVrWlhnaU9qSjlmUT09IiwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6
QUJDREVGR0hJSksifYXE3G0AAADCAAAASxf5/MoLOmV2ZW50LXR5cGUHAAVjaHVuaw06Y29udGVu
dC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImJ5dGVzIjoi
ZXlKamIyNTBaVzUwUW14dlkydFRkRzl3SWpwN0ltTnZiblJsYm5SQ2JHOWphMGx1WkdWNElqb3lm
WDA9IiwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eCJ9qa04SwAAAM0AAABLlalrGws6ZXZl
bnQtdHlwZQcABWNodW5rDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdl
LXR5cGUHAAVldmVudHsiYnl0ZXMiOiJleUpqYjI1MFpXNTBRbXh2WTJ0RVpXeDBZU0k2ZXlKa1pX
eDBZU0k2ZXlKMFpYaDBJam9pSUhsdmRTSjlMQ0pqYjI1MFpXNTBRbXh2WTJ0SmJtUmxlQ0k2TTMx
OSIsInAiOiJhYmMifRT7tlwAAADeAAAAS7LphkkLOmV2ZW50LXR5cGUHAAVjaHVuaw06Y29udGVu
dC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImJ5dGVzIjoi
ZXlKamIyNTBaVzUwUW14dlkydFRkRzl3SWpwN0ltTnZiblJsYm5SQ2JHOWphMGx1WkdWNElqb3pm
WDA9IiwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RV
VldYWVoifZUya0cAAADwAAAAS8wYFywLOmV2ZW50LXR5cGUHAAVjaHVuaw06Y29udGVudC10eXBl
BwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImJ5dGVzIjoiZXlKamIy
NTBaVzUwUW14dlkydEVaV3gwWVNJNmV5SmtaV3gwWVNJNmV5SjBaWGgwSWpvaUp5SjlMQ0pqYjI1
MFpXNTBRbXh2WTJ0SmJtUmxlQ0k2TkgxOSIsInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5
ekFCQ0RFRkdISUpLTE1OT1AifViTWGoAAAC0AAAAS2Fr6aULOmV2ZW50LXR5cGUHAAVjaHVuaw06
Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImJ5
dGVzIjoiZXlKamIyNTBaVzUwUW14dlkydFRkRzl3SWpwN0ltTnZiblJsYm5SQ2JHOWphMGx1WkdW
NElqbzBmWDA9IiwicCI6ImFiY2RlZmdoaWoifbI54e4AAADyAAAAS7bYREwLOmV2ZW50LXR5cGUH
AAVjaHVuaw06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAF
ZXZlbnR7ImJ5dGVzIjoiZXlKamIyNTBaVzUwUW14dlkydEVaV3gwWVNJNmV5SmtaV3gwWVNJNmV5
SjBaWGgwSWpvaWRtVWlmU3dpWTI5dWRHVnVkRUpzYjJOclNXNWtaWGdpT2pWOWZRPT0iLCJwIjoi
YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTiJ9j3DJqQAAAMMAAABLKpnV
egs6ZXZlbnQtdHlwZQcABWNodW5rDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTpt
ZXNzYWdlLXR5cGUHAAVldmVudHsiYnl0ZXMiOiJleUpqYjI1MFpXNTBRbXh2WTJ0VGRHOXdJanA3
SW1OdmJuUmxiblJDYkc5amEwbHVaR1Y0SWpvMWZYMD0iLCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFy
c3R1dnd4eSJ9F6CZmwAAAQcAAABL/VBIxAs6ZXZlbnQtdHlwZQcABWNodW5rDTpjb250ZW50LXR5
cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiYnl0ZXMiOiJleUpq
YjI1MFpXNTBRbXh2WTJ0RVpXeDBZU0k2ZXlKa1pXeDBZU0k2ZXlKMFpYaDBJam9pSUdsemMzVmxa
Q0o5TENKamIyNTBaVzUwUW14dlkydEpibVJsZUNJNk5uMTkiLCJwIjoiYWJjZGVmZ2hpamtsbW5v
cHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0In2LnbEKAAAAtQAAAEtc
C8AVCzpldmVudC10eXBlBwAFY2h1bmsNOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24N
Om1lc3NhZ2UtdHlwZQcABWV2ZW50eyJieXRlcyI6ImV5SmpiMjUwWlc1MFFteHZZMnRUZEc5d0lq
cDdJbU52Ym5SbGJuUkNiRzlqYTBsdVpHVjRJam8yZlgwPSIsInAiOiJhYmNkZWZnaGlqayJ92s5l
DQAAAN0AAABL9Un8mQs6ZXZlbnQtdHlwZQcABWNodW5rDTpjb250ZW50LXR5cGUHABBhcHBsaWNh
dGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiYnl0ZXMiOiJleUpqYjI1MFpXNTBRbXh2
WTJ0RVpXeDBZU0k2ZXlKa1pXeDBZU0k2ZXlKMFpYaDBJam9pSUdFaWZTd2lZMjl1ZEdWdWRFSnNi
Mk5yU1c1a1pYZ2lPamQ5ZlE9PSIsInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzIn2i7NJQAAAA0AAA
AEsN2TgoCzpldmVudC10eXBlBwAFY2h1bmsNOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pz
b24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJieXRlcyI6ImV5SmpiMjUwWlc1MFFteHZZMnRUZEc5
d0lqcDdJbU52Ym5SbGJuUkNiRzlqYTBsdVpHVjRJam8zZlgwPSIsInAiOiJhYmNkZWZnaGlqa2xt
bm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTCJ9vFdU3wAAAP8AAABLTkiA/Qs6ZXZlbnQtdHlwZQcA
BWNodW5rDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVl
dmVudHsiYnl0ZXMiOiJleUpqYjI1MFpXNTBRbXh2WTJ0RVpXeDBZU0k2ZXlKa1pXeDBZU0k2ZXlK
MFpYaDBJam9pSUhSbGMzUWlmU3dpWTI5dWRHVnVkRUpzYjJOclNXNWtaWGdpT2poOWZRPT0iLCJw
IjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWVyJ9KX8k
OAAAAMwAAABLqMlCqws6ZXZlbnQtdHlwZQcABWNodW5rDTpjb250ZW50LXR5cGUHABBhcHBsaWNh
dGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiYnl0ZXMiOiJleUpqYjI1MFpXNTBRbXh2
WTJ0VGRHOXdJanA3SW1OdmJuUmxiblJDYkc5amEwbHVaR1Y0SWpvNGZYMD0iLCJwIjoiYWJjZGVm
Z2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSCJ9PV9naQAAAPAAAABLzBgXLAs6ZXZlbnQtdHlw
ZQcABWNodW5rDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUH
AAVldmVudHsiYnl0ZXMiOiJleUpqYjI1MFpXNTBRbXh2WTJ0RVpXeDBZU0k2ZXlKa1pXeDBZU0k2
ZXlKMFpYaDBJam9pSUhCeWIyMXdkQ0o5TENKamIyNTBaVzUwUW14dlkydEpibVJsZUNJNk9YMTki
LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSCJ9r7jZaQAAANEAAABLMLkR
mAs6ZXZlbnQtdHlwZQcABWNodW5rDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTpt
ZXNzYWdlLXR5cGUHAAVldmVudHsiYnl0ZXMiOiJleUpqYjI1MFpXNTBRbXh2WTJ0VGRHOXdJanA3
SW1OdmJuUmxiblJDYkc5amEwbHVaR1Y0SWpvNWZYMD0iLCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFy
c3R1dnd4eXpBQkNERUZHSElKS0xNIn3bLXYKAAAA3QAAAEv1SfyZCzpldmVudC10eXBlBwAFY2h1
bmsNOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50
eyJieXRlcyI6ImV5SnRaWE56WVdkbFUzUnZjQ0k2ZXlKemRHOXdVbVZoYzI5dUlqb2liV0Y0WDNS
dmEyVnVjeUo5ZlE9PSIsInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpL
TE1OT1BRUlNUVVZXWFkifTuIaJUAAAGLAAAAS4lGFVcLOmV2ZW50LXR5cGUHAAVjaHVuaw06Y29u
dGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImJ5dGVz
IjoiZXlKdFpYUmhaR0YwWVNJNmV5SjFjMkZuWlNJNmV5SnBibkIxZEZSdmEyVnVjeUk2TlN3aWIz
VjBjSFYwVkc5clpXNXpJam94TUgwc0ltMWxkSEpwWTNNaU9udDlMQ0owY21GalpTSTZlMzE5TENK
aGJXRjZiMjR0WW1Wa2NtOWpheTFwYm5adlkyRjBhVzl1VFdWMGNtbGpjeUk2ZXlKcGJuQjFkRlJ2
YTJWdVEyOTFiblFpT2pVc0ltOTFkSEIxZEZSdmEyVnVRMjkxYm5RaU9qRXdMQ0pwYm5adlkyRjBh
Vzl1VEdGMFpXNWplU0k2TVRjM0xDSm1hWEp6ZEVKNWRHVk1ZWFJsYm1ONUlqbzFPWDE5IiwicCI6
ImFiY2RlZmdoaSJ9lvCfnQ==
headers:
Connection:
- keep-alive
Content-Type:
- application/vnd.amazon.eventstream
Date:
- Fri, 24 Jan 2025 13:44:37 GMT
Set-Cookie: test_set_cookie
Transfer-Encoding:
- chunked
X-Amzn-Bedrock-Content-Type:
- application/json
x-amzn-RequestId:
- 632c3a74-f6a4-43e5-b8ff-9c2f84daf7a6
status:
code: 200
message: OK
version: 1

View File

@ -0,0 +1,61 @@
interactions:
- request:
body: '{"inputText": "Say this is a test", "textGenerationConfig": {"maxTokenCount":
10, "temperature": 0.8, "topP": 1, "stopSequences": ["|"]}}'
headers:
Content-Length:
- '137'
User-Agent:
- !!binary |
Qm90bzMvMS4zNS41NiBtZC9Cb3RvY29yZSMxLjM1LjU2IHVhLzIuMCBvcy9saW51eCM2LjEuMC0x
MDM0LW9lbSBtZC9hcmNoI3g4Nl82NCBsYW5nL3B5dGhvbiMzLjEwLjEyIG1kL3B5aW1wbCNDUHl0
aG9uIGNmZy9yZXRyeS1tb2RlI2xlZ2FjeSBCb3RvY29yZS8xLjM1LjU2
X-Amz-Date:
- !!binary |
MjAyNTAxMjRUMTM0NDM3Wg==
X-Amz-Security-Token:
- test_aws_security_token
X-Amzn-Trace-Id:
- !!binary |
Um9vdD0xLTZmYzFlYzExLTczOTA3MmQwMDhhNzRhNjI3ZDg2NDI4ODtQYXJlbnQ9ZGQ0MjJhMjdl
MDdiMDU4NjtTYW1wbGVkPTE=
amz-sdk-invocation-id:
- !!binary |
OTNhOWIwYTctMGJmNi00NGI4LWJlNzItNDFiY2Y0NzdjNWQ5
amz-sdk-request:
- !!binary |
YXR0ZW1wdD0x
authorization:
- Bearer test_aws_authorization
method: POST
uri: https://bedrock-runtime.us-east-1.amazonaws.com/model/amazon.titan-text-lite-v1/invoke-with-response-stream
response:
body:
string: !!binary |
AAAB9QAAAEvPpEv5CzpldmVudC10eXBlBwAFY2h1bmsNOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0
aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJieXRlcyI6ImV5SnZkWFJ3ZFhSVVpYaDBJ
am9pTGx4dVRXOXlaU0JwYm1admNtMWhkR2x2YmlCM2FXeHNJR0psSUc1bFpXUmxaQ0JpWldadmNt
VWdZU0J3Y205d1pYSWlMQ0pwYm1SbGVDSTZNQ3dpZEc5MFlXeFBkWFJ3ZFhSVVpYaDBWRzlyWlc1
RGIzVnVkQ0k2TVRBc0ltTnZiWEJzWlhScGIyNVNaV0Z6YjI0aU9pSk1SVTVIVkVnaUxDSnBibkIx
ZEZSbGVIUlViMnRsYmtOdmRXNTBJam8xTENKaGJXRjZiMjR0WW1Wa2NtOWpheTFwYm5adlkyRjBh
Vzl1VFdWMGNtbGpjeUk2ZXlKcGJuQjFkRlJ2YTJWdVEyOTFiblFpT2pVc0ltOTFkSEIxZEZSdmEy
VnVRMjkxYm5RaU9qRXdMQ0pwYm5adlkyRjBhVzl1VEdGMFpXNWplU0k2TnpBNExDSm1hWEp6ZEVK
NWRHVk1ZWFJsYm1ONUlqbzNNRGQ5ZlE9PSIsInAiOiJhYmNkZWZnIn2cuo/H
headers:
Connection:
- keep-alive
Content-Type:
- application/vnd.amazon.eventstream
Date:
- Fri, 24 Jan 2025 13:44:38 GMT
Set-Cookie: test_set_cookie
Transfer-Encoding:
- chunked
X-Amzn-Bedrock-Content-Type:
- application/json
x-amzn-RequestId:
- 47aaeeb3-fa59-4aae-b480-01632279e2fa
status:
code: 200
message: OK
version: 1

View File

@ -0,0 +1,124 @@
interactions:
- request:
body: '{"messages": [{"role": "user", "content": [{"text": "Say this is a test",
"type": "text"}]}], "anthropic_version": "bedrock-2023-05-31", "max_tokens":
10, "temperature": 0.8, "top_p": 1, "stop_sequences": ["|"]}'
headers:
Content-Length:
- '211'
User-Agent:
- !!binary |
Qm90bzMvMS4zNS41NiBtZC9Cb3RvY29yZSMxLjM1LjU2IHVhLzIuMCBvcy9saW51eCM2LjEuMC0x
MDM0LW9lbSBtZC9hcmNoI3g4Nl82NCBsYW5nL3B5dGhvbiMzLjEwLjEyIG1kL3B5aW1wbCNDUHl0
aG9uIGNmZy9yZXRyeS1tb2RlI2xlZ2FjeSBCb3RvY29yZS8xLjM1LjU2
X-Amz-Date:
- !!binary |
MjAyNTAxMjRUMTM0NDM4Wg==
X-Amz-Security-Token:
- test_aws_security_token
X-Amzn-Trace-Id:
- !!binary |
Um9vdD0xLWY5MjBjYzFhLTI1ZGI4MTgwYTZiOGQ3YWQ0MDI0Zjg3YTtQYXJlbnQ9NDhlOTc1MmFm
NjZjMTA5ODtTYW1wbGVkPTE=
amz-sdk-invocation-id:
- !!binary |
NGQ1NzllYzAtZDIxZi00NTVhLTkxOGMtNDgxNjE3ZjliZjQx
amz-sdk-request:
- !!binary |
YXR0ZW1wdD0x
authorization:
- Bearer test_aws_authorization
method: POST
uri: https://bedrock-runtime.us-east-1.amazonaws.com/model/anthropic.claude-v2/invoke-with-response-stream
response:
body:
string: !!binary |
AAABsQAAAEti17VwCzpldmVudC10eXBlBwAFY2h1bmsNOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0
aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJieXRlcyI6ImV5SjBlWEJsSWpvaWJXVnpj
MkZuWlY5emRHRnlkQ0lzSW0xbGMzTmhaMlVpT25zaWFXUWlPaUp0YzJkZlltUnlhMTh3TVRaVWNW
Vk5aRU5GY0VWYU5YaDNURGhRYVdwSWJ6VWlMQ0owZVhCbElqb2liV1Z6YzJGblpTSXNJbkp2YkdV
aU9pSmhjM05wYzNSaGJuUWlMQ0p0YjJSbGJDSTZJbU5zWVhWa1pTMHlMakFpTENKamIyNTBaVzUw
SWpwYlhTd2ljM1J2Y0Y5eVpXRnpiMjRpT201MWJHd3NJbk4wYjNCZmMyVnhkV1Z1WTJVaU9tNTFi
R3dzSW5WellXZGxJanA3SW1sdWNIVjBYM1J2YTJWdWN5STZNVFFzSW05MWRIQjFkRjkwYjJ0bGJu
TWlPakY5ZlgwPSIsInAiOiJhYmNkZWZnaGlqayJ9gkyXHwAAAOIAAABL1jjTzgs6ZXZlbnQtdHlw
ZQcABWNodW5rDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUH
AAVldmVudHsiYnl0ZXMiOiJleUowZVhCbElqb2lZMjl1ZEdWdWRGOWliRzlqYTE5emRHRnlkQ0lz
SW1sdVpHVjRJam93TENKamIyNTBaVzUwWDJKc2IyTnJJanA3SW5SNWNHVWlPaUowWlhoMElpd2lk
R1Y0ZENJNklpSjlmUT09IiwicCI6ImFiY2QifScLG7kAAAEOAAAAS/BAKrULOmV2ZW50LXR5cGUH
AAVjaHVuaw06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAF
ZXZlbnR7ImJ5dGVzIjoiZXlKMGVYQmxJam9pWTI5dWRHVnVkRjlpYkc5amExOWtaV3gwWVNJc0lt
bHVaR1Y0SWpvd0xDSmtaV3gwWVNJNmV5SjBlWEJsSWpvaWRHVjRkRjlrWld4MFlTSXNJblJsZUhR
aU9pSlBhMkY1SW4xOSIsInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpL
TE1OT1BRUlNUVVYifZyNweMAAADxAAAAS/F4PpwLOmV2ZW50LXR5cGUHAAVjaHVuaw06Y29udGVu
dC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImJ5dGVzIjoi
ZXlKMGVYQmxJam9pWTI5dWRHVnVkRjlpYkc5amExOWtaV3gwWVNJc0ltbHVaR1Y0SWpvd0xDSmta
V3gwWVNJNmV5SjBlWEJsSWpvaWRHVjRkRjlrWld4MFlTSXNJblJsZUhRaU9pSXNJbjE5IiwicCI6
ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3In2bsnIkAAABAQAAAEtyEL1kCzpldmVudC10eXBlBwAF
Y2h1bmsNOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2
ZW50eyJieXRlcyI6ImV5SjBlWEJsSWpvaVkyOXVkR1Z1ZEY5aWJHOWphMTlrWld4MFlTSXNJbWx1
WkdWNElqb3dMQ0prWld4MFlTSTZleUowZVhCbElqb2lkR1Y0ZEY5a1pXeDBZU0lzSW5SbGVIUWlP
aUlnU1NKOWZRPT0iLCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSEkifS+F
e3sAAAEFAAAAS4eQG6QLOmV2ZW50LXR5cGUHAAVjaHVuaw06Y29udGVudC10eXBlBwAQYXBwbGlj
YXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImJ5dGVzIjoiZXlKMGVYQmxJam9pWTI5
dWRHVnVkRjlpYkc5amExOWtaV3gwWVNJc0ltbHVaR1Y0SWpvd0xDSmtaV3gwWVNJNmV5SjBlWEJs
SWpvaWRHVjRkRjlrWld4MFlTSXNJblJsZUhRaU9pSWdkMmxzYkNKOWZRPT0iLCJwIjoiYWJjZGVm
Z2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSEkifXVHT8sAAAD2AAAAS0NY4owLOmV2ZW50LXR5
cGUHAAVjaHVuaw06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBl
BwAFZXZlbnR7ImJ5dGVzIjoiZXlKMGVYQmxJam9pWTI5dWRHVnVkRjlpYkc5amExOWtaV3gwWVNJ
c0ltbHVaR1Y0SWpvd0xDSmtaV3gwWVNJNmV5SjBlWEJsSWpvaWRHVjRkRjlrWld4MFlTSXNJblJs
ZUhRaU9pSWdjMkY1SW4xOSIsInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3gifdFfmr0AAAD2
AAAAS0NY4owLOmV2ZW50LXR5cGUHAAVjaHVuaw06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24v
anNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImJ5dGVzIjoiZXlKMGVYQmxJam9pWTI5dWRHVnVk
RjlpYkc5amExOWtaV3gwWVNJc0ltbHVaR1Y0SWpvd0xDSmtaV3gwWVNJNmV5SjBlWEJsSWpvaWRH
VjRkRjlrWld4MFlTSXNJblJsZUhRaU9pSWdYQ0lpZlgwPSIsInAiOiJhYmNkZWZnaGlqa2xtbm9w
cXJzdHV2d3gifXU4Q4UAAADzAAAAS4u4bfwLOmV2ZW50LXR5cGUHAAVjaHVuaw06Y29udGVudC10
eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImJ5dGVzIjoiZXlK
MGVYQmxJam9pWTI5dWRHVnVkRjlpYkc5amExOWtaV3gwWVNJc0ltbHVaR1Y0SWpvd0xDSmtaV3gw
WVNJNmV5SjBlWEJsSWpvaWRHVjRkRjlrWld4MFlTSXNJblJsZUhRaU9pSlVhR2x6SW4xOSIsInAi
OiJhYmNkZWZnaGlqa2xtbm9wcXJzdHUifZY82M0AAAEPAAAAS80gAwULOmV2ZW50LXR5cGUHAAVj
aHVuaw06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZl
bnR7ImJ5dGVzIjoiZXlKMGVYQmxJam9pWTI5dWRHVnVkRjlpYkc5amExOWtaV3gwWVNJc0ltbHVa
R1Y0SWpvd0xDSmtaV3gwWVNJNmV5SjBlWEJsSWpvaWRHVjRkRjlrWld4MFlTSXNJblJsZUhRaU9p
SWdhWE1pZlgwPSIsInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1O
T1BRUlNUVVZXIn2PKfsQAAAA+wAAAEu7yCY9CzpldmVudC10eXBlBwAFY2h1bmsNOmNvbnRlbnQt
dHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJieXRlcyI6ImV5
SjBlWEJsSWpvaVkyOXVkR1Z1ZEY5aWJHOWphMTlrWld4MFlTSXNJbWx1WkdWNElqb3dMQ0prWld4
MFlTSTZleUowZVhCbElqb2lkR1Y0ZEY5a1pXeDBZU0lzSW5SbGVIUWlPaUlnWVNKOWZRPT0iLCJw
IjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkMifWGL95MAAAEKAAAASwXAjHULOmV2ZW50
LXR5cGUHAAVjaHVuaw06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10
eXBlBwAFZXZlbnR7ImJ5dGVzIjoiZXlKMGVYQmxJam9pWTI5dWRHVnVkRjlpYkc5amExOWtaV3gw
WVNJc0ltbHVaR1Y0SWpvd0xDSmtaV3gwWVNJNmV5SjBlWEJsSWpvaWRHVjRkRjlrWld4MFlTSXNJ
blJsZUhRaU9pSWdkR1Z6ZENKOWZRPT0iLCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpB
QkNERUZHSElKS0xNTiJ9xf99iwAAALwAAABLURuiZAs6ZXZlbnQtdHlwZQcABWNodW5rDTpjb250
ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiYnl0ZXMi
OiJleUowZVhCbElqb2lZMjl1ZEdWdWRGOWliRzlqYTE5emRHOXdJaXdpYVc1a1pYZ2lPakI5Iiwi
cCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6In0ErvuiAAABDgAAAEvwQCq1CzpldmVudC10
eXBlBwAFY2h1bmsNOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlw
ZQcABWV2ZW50eyJieXRlcyI6ImV5SjBlWEJsSWpvaWJXVnpjMkZuWlY5a1pXeDBZU0lzSW1SbGJI
UmhJanA3SW5OMGIzQmZjbVZoYzI5dUlqb2liV0Y0WDNSdmEyVnVjeUlzSW5OMGIzQmZjMlZ4ZFdW
dVkyVWlPbTUxYkd4OUxDSjFjMkZuWlNJNmV5SnZkWFJ3ZFhSZmRHOXJaVzV6SWpveE1IMTkiLCJw
IjoiYWJjZGVmZ2hpamtsIn0VL5oQAAABSQAAAEsak67sCzpldmVudC10eXBlBwAFY2h1bmsNOmNv
bnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJieXRl
cyI6ImV5SjBlWEJsSWpvaWJXVnpjMkZuWlY5emRHOXdJaXdpWVcxaGVtOXVMV0psWkhKdlkyc3Rh
VzUyYjJOaGRHbHZiazFsZEhKcFkzTWlPbnNpYVc1d2RYUlViMnRsYmtOdmRXNTBJam94TkN3aWIz
VjBjSFYwVkc5clpXNURiM1Z1ZENJNk1UQXNJbWx1ZG05allYUnBiMjVNWVhSbGJtTjVJam8xT1Rj
c0ltWnBjbk4wUW5sMFpVeGhkR1Z1WTNraU9qSTVNMzE5IiwicCI6ImFiY2RlZmdoaWprbG1ub3Bx
cnMifV7iQSc=
headers:
Connection:
- keep-alive
Content-Type:
- application/vnd.amazon.eventstream
Date:
- Fri, 24 Jan 2025 13:44:39 GMT
Set-Cookie: test_set_cookie
Transfer-Encoding:
- chunked
X-Amzn-Bedrock-Content-Type:
- application/json
x-amzn-RequestId:
- e52df188-e57f-43bb-a1bf-cfb42fd11fcd
status:
code: 200
message: OK
version: 1

View File

@ -27,7 +27,7 @@ from opentelemetry.trace.status import StatusCode
from .bedrock_utils import (
assert_completion_attributes_from_streaming_body,
assert_converse_completion_attributes,
assert_converse_stream_completion_attributes,
assert_stream_completion_attributes,
)
BOTO3_VERSION = tuple(int(x) for x in boto3.__version__.split("."))
@ -149,9 +149,12 @@ def test_converse_stream_with_content(
output_tokens = usage["outputTokens"]
assert text
assert finish_reason
assert input_tokens
assert output_tokens
(span,) = span_exporter.get_finished_spans()
assert_converse_stream_completion_attributes(
assert_stream_completion_attributes(
span,
llm_model_value,
input_tokens,
@ -188,7 +191,7 @@ def test_converse_stream_with_invalid_model(
)
(span,) = span_exporter.get_finished_spans()
assert_converse_stream_completion_attributes(
assert_stream_completion_attributes(
span,
llm_model_value,
operation_name="chat",
@ -322,3 +325,118 @@ def test_invoke_model_with_invalid_model(
logs = log_exporter.get_finished_logs()
assert len(logs) == 0
@pytest.mark.parametrize(
"model_family",
["amazon.nova", "amazon.titan", "anthropic.claude"],
)
@pytest.mark.vcr()
def test_invoke_model_with_response_stream_with_content(
span_exporter,
log_exporter,
bedrock_runtime_client,
instrument_with_content,
model_family,
):
# pylint:disable=too-many-locals
llm_model_value = get_model_name_from_family(model_family)
max_tokens, temperature, top_p, stop_sequences = 10, 0.8, 1, ["|"]
body = get_invoke_model_body(
llm_model_value, max_tokens, temperature, top_p, stop_sequences
)
response = bedrock_runtime_client.invoke_model_with_response_stream(
body=body,
modelId=llm_model_value,
)
# consume the stream in order to have it traced
finish_reason = None
input_tokens, output_tokens = None, None
text = ""
for event in response["body"]:
json_bytes = event["chunk"].get("bytes", b"")
decoded = json_bytes.decode("utf-8")
chunk = json.loads(decoded)
# amazon.titan
if (stop_reason := chunk.get("completionReason")) is not None:
finish_reason = stop_reason
if (output_text := chunk.get("outputText")) is not None:
text += output_text
# amazon.titan, anthropic.claude
if invocation_metrics := chunk.get("amazon-bedrock-invocationMetrics"):
input_tokens = invocation_metrics["inputTokenCount"]
output_tokens = invocation_metrics["outputTokenCount"]
# anthropic.claude
if (message_type := chunk.get("type")) is not None:
if message_type == "content_block_start":
text += chunk["content_block"]["text"]
elif message_type == "content_block_delta":
text += chunk["delta"]["text"]
elif message_type == "message_delta":
finish_reason = chunk["delta"]["stop_reason"]
# amazon nova
if "contentBlockDelta" in chunk:
text += chunk["contentBlockDelta"]["delta"]["text"]
if "messageStop" in chunk:
finish_reason = chunk["messageStop"]["stopReason"]
if "metadata" in chunk:
usage = chunk["metadata"]["usage"]
input_tokens = usage["inputTokens"]
output_tokens = usage["outputTokens"]
assert text
assert finish_reason
assert input_tokens
assert output_tokens
(span,) = span_exporter.get_finished_spans()
assert_stream_completion_attributes(
span,
llm_model_value,
input_tokens,
output_tokens,
(finish_reason,),
"text_completion" if model_family == "amazon.titan" else "chat",
top_p,
temperature,
max_tokens,
stop_sequences,
)
logs = log_exporter.get_finished_logs()
assert len(logs) == 0
@pytest.mark.vcr()
def test_invoke_model_with_response_stream_invalid_model(
span_exporter,
log_exporter,
bedrock_runtime_client,
instrument_with_content,
):
llm_model_value = "does-not-exist"
with pytest.raises(bedrock_runtime_client.exceptions.ClientError):
bedrock_runtime_client.invoke_model_with_response_stream(
body=b"",
modelId=llm_model_value,
)
(span,) = span_exporter.get_finished_spans()
assert_completion_attributes_from_streaming_body(
span,
llm_model_value,
None,
"chat",
)
assert span.status.status_code == StatusCode.ERROR
assert span.attributes[ERROR_TYPE] == "ValidationException"
logs = log_exporter.get_finished_logs()
assert len(logs) == 0