opentelemetry-instrumentation-botocore 0.54b1__tar.gz → 0.55b0__tar.gz
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.
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/PKG-INFO +4 -5
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/pyproject.toml +3 -4
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/src/opentelemetry/instrumentation/botocore/__init__.py +4 -2
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/src/opentelemetry/instrumentation/botocore/extensions/bedrock.py +38 -23
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/src/opentelemetry/instrumentation/botocore/extensions/bedrock_utils.py +54 -12
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/src/opentelemetry/instrumentation/botocore/version.py +1 -1
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/bedrock_utils.py +0 -2
- opentelemetry_instrumentation_botocore-0.55b0/tests/cassettes/test_converse_stream_close_before_consumption.yaml +81 -0
- opentelemetry_instrumentation_botocore-0.55b0/tests/cassettes/test_converse_stream_tool_call_parsing_errors.yaml +487 -0
- opentelemetry_instrumentation_botocore-0.55b0/tests/cassettes/test_invoke_model_with_content_assistant_content_as_string.yaml +78 -0
- opentelemetry_instrumentation_botocore-0.55b0/tests/cassettes/test_invoke_model_with_response_stream_close_before_consumption[amazon.nova].yaml +106 -0
- opentelemetry_instrumentation_botocore-0.55b0/tests/cassettes/test_invoke_model_with_response_stream_close_before_consumption[amazon.titan].yaml +65 -0
- opentelemetry_instrumentation_botocore-0.55b0/tests/cassettes/test_invoke_model_with_response_stream_close_before_consumption[anthropic.claude].yaml +136 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/test_botocore_bedrock.py +280 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/test_botocore_instrumentation.py +5 -2
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/test_botocore_lambda.py +1 -1
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/.gitignore +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/LICENSE +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/README.rst +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/src/opentelemetry/instrumentation/botocore/environment_variables.py +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/src/opentelemetry/instrumentation/botocore/extensions/__init__.py +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/src/opentelemetry/instrumentation/botocore/extensions/_messaging.py +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/src/opentelemetry/instrumentation/botocore/extensions/dynamodb.py +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/src/opentelemetry/instrumentation/botocore/extensions/lmbd.py +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/src/opentelemetry/instrumentation/botocore/extensions/sns.py +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/src/opentelemetry/instrumentation/botocore/extensions/sqs.py +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/src/opentelemetry/instrumentation/botocore/extensions/types.py +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/src/opentelemetry/instrumentation/botocore/package.py +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/src/opentelemetry/instrumentation/botocore/utils.py +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/README.md +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/__init__.py +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_converse_no_content.yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_converse_no_content_different_events.yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_converse_stream_handles_event_stream_error.yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_converse_stream_no_content.yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_converse_stream_no_content_different_events.yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_converse_stream_no_content_tool_call.yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_converse_stream_with_content.yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_converse_stream_with_content_different_events.yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_converse_stream_with_content_tool_call.yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_converse_stream_with_invalid_model.yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_converse_tool_call_no_content.yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_converse_tool_call_with_content.yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_converse_with_content.yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_converse_with_content_different_events.yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_converse_with_invalid_model.yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_invoke_model_no_content[amazon.nova].yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_invoke_model_no_content[amazon.titan].yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_invoke_model_no_content[anthropic.claude].yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_invoke_model_no_content[cohere.command-r].yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_invoke_model_no_content[cohere.command].yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_invoke_model_no_content[meta.llama].yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_invoke_model_no_content[mistral.mistral].yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_invoke_model_no_content_different_events[amazon.nova].yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_invoke_model_no_content_different_events[anthropic.claude].yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_invoke_model_no_content_tool_call[amazon.nova].yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_invoke_model_no_content_tool_call[anthropic.claude].yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_invoke_model_with_content[amazon.nova].yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_invoke_model_with_content[amazon.titan].yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_invoke_model_with_content[anthropic.claude].yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_invoke_model_with_content[cohere.command-r].yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_invoke_model_with_content[cohere.command].yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_invoke_model_with_content[meta.llama].yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_invoke_model_with_content[mistral.mistral].yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_invoke_model_with_content_different_events[amazon.nova].yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_invoke_model_with_content_different_events[anthropic.claude].yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_invoke_model_with_content_tool_call[amazon.nova].yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_invoke_model_with_content_tool_call[anthropic.claude].yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_invoke_model_with_content_user_content_as_string.yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_invoke_model_with_invalid_model.yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_invoke_model_with_response_stream_handles_stream_error.yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_invoke_model_with_response_stream_invalid_model.yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_invoke_model_with_response_stream_no_content[amazon.nova].yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_invoke_model_with_response_stream_no_content[amazon.titan].yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_invoke_model_with_response_stream_no_content[anthropic.claude].yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_invoke_model_with_response_stream_no_content_different_events[amazon.nova].yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_invoke_model_with_response_stream_no_content_different_events[anthropic.claude].yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_invoke_model_with_response_stream_no_content_tool_call[amazon.nova].yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_invoke_model_with_response_stream_no_content_tool_call[anthropic.claude].yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_invoke_model_with_response_stream_with_content[amazon.nova].yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_invoke_model_with_response_stream_with_content[amazon.titan].yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_invoke_model_with_response_stream_with_content[anthropic.claude].yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_invoke_model_with_response_stream_with_content_different_events[amazon.nova].yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_invoke_model_with_response_stream_with_content_different_events[anthropic.claude].yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_invoke_model_with_response_stream_with_content_tool_call[amazon.nova].yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/cassettes/test_invoke_model_with_response_stream_with_content_tool_call[anthropic.claude].yaml +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/conftest.py +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/test_botocore_dynamodb.py +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/test_botocore_messaging.py +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/test_botocore_sns.py +0 -0
- {opentelemetry_instrumentation_botocore-0.54b1 → opentelemetry_instrumentation_botocore-0.55b0}/tests/test_botocore_sqs.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: opentelemetry-instrumentation-botocore
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.55b0
|
4
4
|
Summary: OpenTelemetry Botocore instrumentation
|
5
5
|
Project-URL: Homepage, https://github.com/open-telemetry/opentelemetry-python-contrib/tree/main/instrumentation/opentelemetry-instrumentation-botocore
|
6
6
|
Project-URL: Repository, https://github.com/open-telemetry/opentelemetry-python-contrib
|
@@ -12,17 +12,16 @@ Classifier: Intended Audience :: Developers
|
|
12
12
|
Classifier: License :: OSI Approved :: Apache Software License
|
13
13
|
Classifier: Programming Language :: Python
|
14
14
|
Classifier: Programming Language :: Python :: 3
|
15
|
-
Classifier: Programming Language :: Python :: 3.8
|
16
15
|
Classifier: Programming Language :: Python :: 3.9
|
17
16
|
Classifier: Programming Language :: Python :: 3.10
|
18
17
|
Classifier: Programming Language :: Python :: 3.11
|
19
18
|
Classifier: Programming Language :: Python :: 3.12
|
20
19
|
Classifier: Programming Language :: Python :: 3.13
|
21
|
-
Requires-Python: >=3.
|
20
|
+
Requires-Python: >=3.9
|
22
21
|
Requires-Dist: opentelemetry-api~=1.30
|
23
|
-
Requires-Dist: opentelemetry-instrumentation==0.
|
22
|
+
Requires-Dist: opentelemetry-instrumentation==0.55b0
|
24
23
|
Requires-Dist: opentelemetry-propagator-aws-xray~=1.0
|
25
|
-
Requires-Dist: opentelemetry-semantic-conventions==0.
|
24
|
+
Requires-Dist: opentelemetry-semantic-conventions==0.55b0
|
26
25
|
Provides-Extra: instruments
|
27
26
|
Requires-Dist: botocore~=1.0; extra == 'instruments'
|
28
27
|
Description-Content-Type: text/x-rst
|
@@ -8,7 +8,7 @@ dynamic = ["version"]
|
|
8
8
|
description = "OpenTelemetry Botocore instrumentation"
|
9
9
|
readme = "README.rst"
|
10
10
|
license = "Apache-2.0"
|
11
|
-
requires-python = ">=3.
|
11
|
+
requires-python = ">=3.9"
|
12
12
|
authors = [
|
13
13
|
{ name = "OpenTelemetry Authors", email = "cncf-opentelemetry-contributors@lists.cncf.io" },
|
14
14
|
]
|
@@ -18,7 +18,6 @@ classifiers = [
|
|
18
18
|
"License :: OSI Approved :: Apache Software License",
|
19
19
|
"Programming Language :: Python",
|
20
20
|
"Programming Language :: Python :: 3",
|
21
|
-
"Programming Language :: Python :: 3.8",
|
22
21
|
"Programming Language :: Python :: 3.9",
|
23
22
|
"Programming Language :: Python :: 3.10",
|
24
23
|
"Programming Language :: Python :: 3.11",
|
@@ -27,8 +26,8 @@ classifiers = [
|
|
27
26
|
]
|
28
27
|
dependencies = [
|
29
28
|
"opentelemetry-api ~= 1.30",
|
30
|
-
"opentelemetry-instrumentation == 0.
|
31
|
-
"opentelemetry-semantic-conventions == 0.
|
29
|
+
"opentelemetry-instrumentation == 0.55b0",
|
30
|
+
"opentelemetry-semantic-conventions == 0.55b0",
|
32
31
|
"opentelemetry-propagator-aws-xray ~= 1.0",
|
33
32
|
]
|
34
33
|
|
@@ -109,6 +109,9 @@ from opentelemetry.instrumentation.utils import (
|
|
109
109
|
)
|
110
110
|
from opentelemetry.metrics import Instrument, Meter, get_meter
|
111
111
|
from opentelemetry.propagators.aws.aws_xray_propagator import AwsXRayPropagator
|
112
|
+
from opentelemetry.semconv._incubating.attributes.cloud_attributes import (
|
113
|
+
CLOUD_REGION,
|
114
|
+
)
|
112
115
|
from opentelemetry.semconv.trace import SpanAttributes
|
113
116
|
from opentelemetry.trace import get_tracer
|
114
117
|
from opentelemetry.trace.span import Span
|
@@ -276,8 +279,7 @@ class BotocoreInstrumentor(BaseInstrumentor):
|
|
276
279
|
SpanAttributes.RPC_SYSTEM: "aws-api",
|
277
280
|
SpanAttributes.RPC_SERVICE: call_context.service_id,
|
278
281
|
SpanAttributes.RPC_METHOD: call_context.operation,
|
279
|
-
|
280
|
-
"aws.region": call_context.region,
|
282
|
+
CLOUD_REGION: call_context.region,
|
281
283
|
**get_server_attributes(call_context.endpoint_url),
|
282
284
|
}
|
283
285
|
|
@@ -499,18 +499,20 @@ class _BedrockRuntimeExtension(_AwsSdkExtension):
|
|
499
499
|
[stop_reason],
|
500
500
|
)
|
501
501
|
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
502
|
+
# In case of an early stream closure, the result may not contain outputs
|
503
|
+
if self._stream_has_output_content(result):
|
504
|
+
event_logger = instrumentor_context.event_logger
|
505
|
+
choice = _Choice.from_converse(result, capture_content)
|
506
|
+
# this path is used by streaming apis, in that case we are already out of the span
|
507
|
+
# context so need to add the span context manually
|
508
|
+
span_ctx = span.get_span_context()
|
509
|
+
event_logger.emit(
|
510
|
+
choice.to_choice_event(
|
511
|
+
trace_id=span_ctx.trace_id,
|
512
|
+
span_id=span_ctx.span_id,
|
513
|
+
trace_flags=span_ctx.trace_flags,
|
514
|
+
)
|
512
515
|
)
|
513
|
-
)
|
514
516
|
|
515
517
|
metrics = instrumentor_context.metrics
|
516
518
|
metrics_attributes = self._extract_metrics_attributes()
|
@@ -602,11 +604,14 @@ class _BedrockRuntimeExtension(_AwsSdkExtension):
|
|
602
604
|
span: Span,
|
603
605
|
exception,
|
604
606
|
instrumentor_context: _BotocoreInstrumentorContext,
|
607
|
+
span_ended: bool,
|
605
608
|
):
|
606
609
|
span.set_status(Status(StatusCode.ERROR, str(exception)))
|
607
610
|
if span.is_recording():
|
608
611
|
span.set_attribute(ERROR_TYPE, type(exception).__qualname__)
|
609
|
-
|
612
|
+
|
613
|
+
if not span_ended:
|
614
|
+
span.end()
|
610
615
|
|
611
616
|
metrics = instrumentor_context.metrics
|
612
617
|
metrics_attributes = {
|
@@ -638,15 +643,17 @@ class _BedrockRuntimeExtension(_AwsSdkExtension):
|
|
638
643
|
result["stream"], EventStream
|
639
644
|
):
|
640
645
|
|
641
|
-
def stream_done_callback(response):
|
646
|
+
def stream_done_callback(response, span_ended):
|
642
647
|
self._converse_on_success(
|
643
648
|
span, response, instrumentor_context, capture_content
|
644
649
|
)
|
645
|
-
span.end()
|
646
650
|
|
647
|
-
|
651
|
+
if not span_ended:
|
652
|
+
span.end()
|
653
|
+
|
654
|
+
def stream_error_callback(exception, span_ended):
|
648
655
|
self._on_stream_error_callback(
|
649
|
-
span, exception, instrumentor_context
|
656
|
+
span, exception, instrumentor_context, span_ended
|
650
657
|
)
|
651
658
|
|
652
659
|
result["stream"] = ConverseStreamWrapper(
|
@@ -677,16 +684,17 @@ class _BedrockRuntimeExtension(_AwsSdkExtension):
|
|
677
684
|
elif self._call_context.operation == "InvokeModelWithResponseStream":
|
678
685
|
if "body" in result and isinstance(result["body"], EventStream):
|
679
686
|
|
680
|
-
def invoke_model_stream_done_callback(response):
|
687
|
+
def invoke_model_stream_done_callback(response, span_ended):
|
681
688
|
# the callback gets data formatted as the simpler converse API
|
682
689
|
self._converse_on_success(
|
683
690
|
span, response, instrumentor_context, capture_content
|
684
691
|
)
|
685
|
-
|
692
|
+
if not span_ended:
|
693
|
+
span.end()
|
686
694
|
|
687
|
-
def invoke_model_stream_error_callback(exception):
|
695
|
+
def invoke_model_stream_error_callback(exception, span_ended):
|
688
696
|
self._on_stream_error_callback(
|
689
|
-
span, exception, instrumentor_context
|
697
|
+
span, exception, instrumentor_context, span_ended
|
690
698
|
)
|
691
699
|
|
692
700
|
result["body"] = InvokeModelWithResponseStreamWrapper(
|
@@ -781,9 +789,11 @@ class _BedrockRuntimeExtension(_AwsSdkExtension):
|
|
781
789
|
GEN_AI_RESPONSE_FINISH_REASONS, [response_body["stopReason"]]
|
782
790
|
)
|
783
791
|
|
784
|
-
|
785
|
-
|
786
|
-
|
792
|
+
# In case of an early stream closure, the result may not contain outputs
|
793
|
+
if self._stream_has_output_content(response_body):
|
794
|
+
event_logger = instrumentor_context.event_logger
|
795
|
+
choice = _Choice.from_converse(response_body, capture_content)
|
796
|
+
event_logger.emit(choice.to_choice_event())
|
787
797
|
|
788
798
|
metrics = instrumentor_context.metrics
|
789
799
|
metrics_attributes = self._extract_metrics_attributes()
|
@@ -1004,3 +1014,8 @@ class _BedrockRuntimeExtension(_AwsSdkExtension):
|
|
1004
1014
|
duration,
|
1005
1015
|
attributes=metrics_attributes,
|
1006
1016
|
)
|
1017
|
+
|
1018
|
+
def _stream_has_output_content(self, response_body: dict[str, Any]):
|
1019
|
+
return (
|
1020
|
+
"output" in response_body and "message" in response_body["output"]
|
1021
|
+
)
|
@@ -64,7 +64,9 @@ class ConverseStreamWrapper(ObjectProxy):
|
|
64
64
|
self._response = {}
|
65
65
|
self._message = None
|
66
66
|
self._content_block = {}
|
67
|
+
self._tool_json_input_buf = ""
|
67
68
|
self._record_message = False
|
69
|
+
self._ended = False
|
68
70
|
|
69
71
|
def __iter__(self):
|
70
72
|
try:
|
@@ -72,7 +74,7 @@ class ConverseStreamWrapper(ObjectProxy):
|
|
72
74
|
self._process_event(event)
|
73
75
|
yield event
|
74
76
|
except EventStreamError as exc:
|
75
|
-
self.
|
77
|
+
self._handle_stream_error(exc)
|
76
78
|
raise
|
77
79
|
|
78
80
|
def _process_event(self, event):
|
@@ -88,28 +90,40 @@ class ConverseStreamWrapper(ObjectProxy):
|
|
88
90
|
# {'contentBlockStart': {'start': {'toolUse': {'toolUseId': 'id', 'name': 'func_name'}}, 'contentBlockIndex': 1}}
|
89
91
|
start = event["contentBlockStart"].get("start", {})
|
90
92
|
if "toolUse" in start:
|
91
|
-
|
92
|
-
self._content_block = {"toolUse": tool_use}
|
93
|
+
self._content_block = {"toolUse": start["toolUse"]}
|
93
94
|
return
|
94
95
|
|
95
96
|
if "contentBlockDelta" in event:
|
96
97
|
# {'contentBlockDelta': {'delta': {'text': "Hello"}, 'contentBlockIndex': 0}}
|
97
98
|
# {'contentBlockDelta': {'delta': {'toolUse': {'input': '{"location":"Seattle"}'}}, 'contentBlockIndex': 1}}
|
99
|
+
# {'contentBlockDelta': {'delta': {'toolUse': {'input': 'a", "Yok'}}, 'contentBlockIndex': 1}}
|
98
100
|
if self._record_message:
|
99
101
|
delta = event["contentBlockDelta"].get("delta", {})
|
100
102
|
if "text" in delta:
|
101
103
|
self._content_block.setdefault("text", "")
|
102
104
|
self._content_block["text"] += delta["text"]
|
103
105
|
elif "toolUse" in delta:
|
104
|
-
|
105
|
-
|
106
|
+
if (
|
107
|
+
input_buf := delta["toolUse"].get("input")
|
108
|
+
) is not None:
|
109
|
+
self._tool_json_input_buf += input_buf
|
106
110
|
return
|
107
111
|
|
108
112
|
if "contentBlockStop" in event:
|
109
113
|
# {'contentBlockStop': {'contentBlockIndex': 0}}
|
110
114
|
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
|
+
)
|
111
124
|
self._message["content"].append(self._content_block)
|
112
125
|
self._content_block = {}
|
126
|
+
self._tool_json_input_buf = ""
|
113
127
|
return
|
114
128
|
|
115
129
|
if "messageStop" in event:
|
@@ -133,11 +147,23 @@ class ConverseStreamWrapper(ObjectProxy):
|
|
133
147
|
|
134
148
|
if output_tokens := usage.get("outputTokens"):
|
135
149
|
self._response["usage"]["outputTokens"] = output_tokens
|
136
|
-
|
137
|
-
self._stream_done_callback(self._response)
|
150
|
+
self._complete_stream(self._response)
|
138
151
|
|
139
152
|
return
|
140
153
|
|
154
|
+
def close(self):
|
155
|
+
self.__wrapped__.close()
|
156
|
+
# Treat the stream as done to ensure the span end.
|
157
|
+
self._complete_stream(self._response)
|
158
|
+
|
159
|
+
def _complete_stream(self, response):
|
160
|
+
self._stream_done_callback(response, self._ended)
|
161
|
+
self._ended = True
|
162
|
+
|
163
|
+
def _handle_stream_error(self, exc):
|
164
|
+
self._stream_error_callback(exc, self._ended)
|
165
|
+
self._ended = True
|
166
|
+
|
141
167
|
|
142
168
|
# pylint: disable=abstract-method
|
143
169
|
class InvokeModelWithResponseStreamWrapper(ObjectProxy):
|
@@ -163,6 +189,20 @@ class InvokeModelWithResponseStreamWrapper(ObjectProxy):
|
|
163
189
|
self._content_block = {}
|
164
190
|
self._tool_json_input_buf = ""
|
165
191
|
self._record_message = False
|
192
|
+
self._ended = False
|
193
|
+
|
194
|
+
def close(self):
|
195
|
+
self.__wrapped__.close()
|
196
|
+
# Treat the stream as done to ensure the span end.
|
197
|
+
self._stream_done_callback(self._response, self._ended)
|
198
|
+
|
199
|
+
def _complete_stream(self, response):
|
200
|
+
self._stream_done_callback(response, self._ended)
|
201
|
+
self._ended = True
|
202
|
+
|
203
|
+
def _handle_stream_error(self, exc):
|
204
|
+
self._stream_error_callback(exc, self._ended)
|
205
|
+
self._ended = True
|
166
206
|
|
167
207
|
def __iter__(self):
|
168
208
|
try:
|
@@ -170,7 +210,7 @@ class InvokeModelWithResponseStreamWrapper(ObjectProxy):
|
|
170
210
|
self._process_event(event)
|
171
211
|
yield event
|
172
212
|
except EventStreamError as exc:
|
173
|
-
self.
|
213
|
+
self._handle_stream_error(exc)
|
174
214
|
raise
|
175
215
|
|
176
216
|
def _process_event(self, event):
|
@@ -213,7 +253,7 @@ class InvokeModelWithResponseStreamWrapper(ObjectProxy):
|
|
213
253
|
self._response["output"] = {
|
214
254
|
"message": {"content": [{"text": chunk["outputText"]}]}
|
215
255
|
}
|
216
|
-
self.
|
256
|
+
self._complete_stream(self._response)
|
217
257
|
|
218
258
|
def _process_amazon_nova_chunk(self, chunk):
|
219
259
|
# pylint: disable=too-many-branches
|
@@ -283,7 +323,7 @@ class InvokeModelWithResponseStreamWrapper(ObjectProxy):
|
|
283
323
|
if output_tokens := usage.get("outputTokens"):
|
284
324
|
self._response["usage"]["outputTokens"] = output_tokens
|
285
325
|
|
286
|
-
self.
|
326
|
+
self._complete_stream(self._response)
|
287
327
|
return
|
288
328
|
|
289
329
|
def _process_anthropic_claude_chunk(self, chunk):
|
@@ -355,7 +395,7 @@ class InvokeModelWithResponseStreamWrapper(ObjectProxy):
|
|
355
395
|
self._record_message = False
|
356
396
|
self._message = None
|
357
397
|
|
358
|
-
self.
|
398
|
+
self._complete_stream(self._response)
|
359
399
|
return
|
360
400
|
|
361
401
|
|
@@ -382,7 +422,9 @@ def extract_tool_calls(
|
|
382
422
|
tool_uses = [item["toolUse"] for item in content if "toolUse" in item]
|
383
423
|
if not tool_uses:
|
384
424
|
tool_uses = [
|
385
|
-
item
|
425
|
+
item
|
426
|
+
for item in content
|
427
|
+
if isinstance(item, dict) and item.get("type") == "tool_use"
|
386
428
|
]
|
387
429
|
tool_id_key = "id"
|
388
430
|
else:
|
@@ -275,8 +275,6 @@ def remove_none_values(body):
|
|
275
275
|
continue
|
276
276
|
if isinstance(value, dict):
|
277
277
|
result[key] = remove_none_values(value)
|
278
|
-
elif isinstance(value, list):
|
279
|
-
result[key] = [remove_none_values(i) for i in value]
|
280
278
|
else:
|
281
279
|
result[key] = value
|
282
280
|
return result
|
@@ -0,0 +1,81 @@
|
|
1
|
+
interactions:
|
2
|
+
- request:
|
3
|
+
body: |-
|
4
|
+
{
|
5
|
+
"messages": [
|
6
|
+
{
|
7
|
+
"role": "user",
|
8
|
+
"content": [
|
9
|
+
{
|
10
|
+
"text": "Say this is a test"
|
11
|
+
}
|
12
|
+
]
|
13
|
+
}
|
14
|
+
],
|
15
|
+
"inferenceConfig": {
|
16
|
+
"maxTokens": 10,
|
17
|
+
"temperature": 0.8,
|
18
|
+
"topP": 1,
|
19
|
+
"stopSequences": [
|
20
|
+
"|"
|
21
|
+
]
|
22
|
+
}
|
23
|
+
}
|
24
|
+
headers:
|
25
|
+
Content-Length:
|
26
|
+
- '170'
|
27
|
+
Content-Type:
|
28
|
+
- application/json
|
29
|
+
User-Agent:
|
30
|
+
- Boto3/1.35.56 md/Botocore#1.35.56 ua/2.0 os/macos#24.4.0 md/arch#arm64 lang/python#3.12.0
|
31
|
+
md/pyimpl#CPython cfg/retry-mode#legacy Botocore/1.35.56
|
32
|
+
X-Amz-Date:
|
33
|
+
- 20250509T104610Z
|
34
|
+
X-Amz-Security-Token:
|
35
|
+
- test_aws_security_token
|
36
|
+
X-Amzn-Trace-Id:
|
37
|
+
- Root=1-98fd1391-6f6d1be3cc209d9ba2fb3034;Parent=6dc095915efed44e;Sampled=1
|
38
|
+
amz-sdk-invocation-id:
|
39
|
+
- 3a37ec88-d989-4397-bfbe-d463b66a3a08
|
40
|
+
amz-sdk-request:
|
41
|
+
- attempt=1
|
42
|
+
authorization:
|
43
|
+
- Bearer test_aws_authorization
|
44
|
+
method: POST
|
45
|
+
uri: https://bedrock-runtime.us-east-1.amazonaws.com/model/amazon.titan-text-lite-v1/converse-stream
|
46
|
+
response:
|
47
|
+
body:
|
48
|
+
string: !!binary |
|
49
|
+
AAAApAAAAFJl4NbnCzpldmVudC10eXBlBwAMbWVzc2FnZVN0YXJ0DTpjb250ZW50LXR5cGUHABBh
|
50
|
+
cHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsicCI6ImFiY2RlZmdoaWprbG1u
|
51
|
+
b3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTSIsInJvbGUiOiJhc3Npc3RhbnQifSKBqDQAAADZAAAA
|
52
|
+
VxTIBhYLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBw
|
53
|
+
bGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4Ijow
|
54
|
+
LCJkZWx0YSI6eyJ0ZXh0IjoiSGksIGRpZCB5b3UgaGF2ZSBhIHF1ZXN0aW9uIn0sInAiOiJhYmNk
|
55
|
+
ZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLIn22h6U3AAAAqgAAAFbdvayfCzpldmVu
|
56
|
+
dC10eXBlBwAQY29udGVudEJsb2NrU3RvcA06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNv
|
57
|
+
bg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJwIjoiYWJjZGVm
|
58
|
+
Z2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0wifQSjvQkAAAChAAAAUTQJCC0LOmV2ZW50
|
59
|
+
LXR5cGUHAAttZXNzYWdlU3RvcA06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVz
|
60
|
+
c2FnZS10eXBlBwAFZXZlbnR7InAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0QiLCJz
|
61
|
+
dG9wUmVhc29uIjoibWF4X3Rva2VucyJ9jxPapgAAAMsAAABOaoNqNAs6ZXZlbnQtdHlwZQcACG1l
|
62
|
+
dGFkYXRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVl
|
63
|
+
dmVudHsibWV0cmljcyI6eyJsYXRlbmN5TXMiOjYyNX0sInAiOiJhYmNkZWZnaGlqa2wiLCJ1c2Fn
|
64
|
+
ZSI6eyJpbnB1dFRva2VucyI6OCwib3V0cHV0VG9rZW5zIjoxMCwidG90YWxUb2tlbnMiOjE4fX0B
|
65
|
+
/Sts
|
66
|
+
headers:
|
67
|
+
Connection:
|
68
|
+
- keep-alive
|
69
|
+
Content-Type:
|
70
|
+
- application/vnd.amazon.eventstream
|
71
|
+
Date:
|
72
|
+
- Fri, 09 May 2025 10:46:10 GMT
|
73
|
+
Set-Cookie: test_set_cookie
|
74
|
+
Transfer-Encoding:
|
75
|
+
- chunked
|
76
|
+
x-amzn-RequestId:
|
77
|
+
- 5aaaa521-d2c6-4980-ba0a-7bba19633a40
|
78
|
+
status:
|
79
|
+
code: 200
|
80
|
+
message: OK
|
81
|
+
version: 1
|