Update AWSBedrock docstrings
This commit is contained in:
@@ -4,6 +4,13 @@
|
|||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
|
"""AWS Bedrock integration for Large Language Model services.
|
||||||
|
|
||||||
|
This module provides AWS Bedrock LLM service implementation with support for
|
||||||
|
Amazon Nova and Anthropic Claude models, including vision capabilities and
|
||||||
|
function calling.
|
||||||
|
"""
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import base64
|
import base64
|
||||||
import copy
|
import copy
|
||||||
@@ -61,17 +68,50 @@ except ModuleNotFoundError as e:
|
|||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class AWSBedrockContextAggregatorPair:
|
class AWSBedrockContextAggregatorPair:
|
||||||
|
"""Container for AWS Bedrock context aggregators.
|
||||||
|
|
||||||
|
Provides convenient access to both user and assistant context aggregators
|
||||||
|
for AWS Bedrock LLM operations.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
_user: The user context aggregator instance.
|
||||||
|
_assistant: The assistant context aggregator instance.
|
||||||
|
"""
|
||||||
|
|
||||||
_user: "AWSBedrockUserContextAggregator"
|
_user: "AWSBedrockUserContextAggregator"
|
||||||
_assistant: "AWSBedrockAssistantContextAggregator"
|
_assistant: "AWSBedrockAssistantContextAggregator"
|
||||||
|
|
||||||
def user(self) -> "AWSBedrockUserContextAggregator":
|
def user(self) -> "AWSBedrockUserContextAggregator":
|
||||||
|
"""Get the user context aggregator.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The user context aggregator instance.
|
||||||
|
"""
|
||||||
return self._user
|
return self._user
|
||||||
|
|
||||||
def assistant(self) -> "AWSBedrockAssistantContextAggregator":
|
def assistant(self) -> "AWSBedrockAssistantContextAggregator":
|
||||||
|
"""Get the assistant context aggregator.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The assistant context aggregator instance.
|
||||||
|
"""
|
||||||
return self._assistant
|
return self._assistant
|
||||||
|
|
||||||
|
|
||||||
class AWSBedrockLLMContext(OpenAILLMContext):
|
class AWSBedrockLLMContext(OpenAILLMContext):
|
||||||
|
"""AWS Bedrock-specific LLM context implementation.
|
||||||
|
|
||||||
|
Extends OpenAI LLM context to handle AWS Bedrock's specific message format
|
||||||
|
and system message handling. Manages conversion between OpenAI and Bedrock
|
||||||
|
message formats.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
messages: List of conversation messages in OpenAI format.
|
||||||
|
tools: List of available function calling tools.
|
||||||
|
tool_choice: Tool selection strategy or specific tool choice.
|
||||||
|
system: System message content for AWS Bedrock.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
messages: Optional[List[dict]] = None,
|
messages: Optional[List[dict]] = None,
|
||||||
@@ -85,6 +125,14 @@ class AWSBedrockLLMContext(OpenAILLMContext):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def upgrade_to_bedrock(obj: OpenAILLMContext) -> "AWSBedrockLLMContext":
|
def upgrade_to_bedrock(obj: OpenAILLMContext) -> "AWSBedrockLLMContext":
|
||||||
|
"""Upgrade an OpenAI LLM context to AWS Bedrock format.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
obj: The OpenAI LLM context to upgrade.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The upgraded AWS Bedrock LLM context.
|
||||||
|
"""
|
||||||
logger.debug(f"Upgrading to AWS Bedrock: {obj}")
|
logger.debug(f"Upgrading to AWS Bedrock: {obj}")
|
||||||
if isinstance(obj, OpenAILLMContext) and not isinstance(obj, AWSBedrockLLMContext):
|
if isinstance(obj, OpenAILLMContext) and not isinstance(obj, AWSBedrockLLMContext):
|
||||||
obj.__class__ = AWSBedrockLLMContext
|
obj.__class__ = AWSBedrockLLMContext
|
||||||
@@ -95,6 +143,14 @@ class AWSBedrockLLMContext(OpenAILLMContext):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_openai_context(cls, openai_context: OpenAILLMContext):
|
def from_openai_context(cls, openai_context: OpenAILLMContext):
|
||||||
|
"""Create AWS Bedrock context from OpenAI context.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
openai_context: The OpenAI LLM context to convert.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
New AWS Bedrock LLM context instance.
|
||||||
|
"""
|
||||||
self = cls(
|
self = cls(
|
||||||
messages=openai_context.messages,
|
messages=openai_context.messages,
|
||||||
tools=openai_context.tools,
|
tools=openai_context.tools,
|
||||||
@@ -106,12 +162,28 @@ class AWSBedrockLLMContext(OpenAILLMContext):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_messages(cls, messages: List[dict]) -> "AWSBedrockLLMContext":
|
def from_messages(cls, messages: List[dict]) -> "AWSBedrockLLMContext":
|
||||||
|
"""Create AWS Bedrock context from message list.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
messages: List of messages in OpenAI format.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
New AWS Bedrock LLM context instance.
|
||||||
|
"""
|
||||||
self = cls(messages=messages)
|
self = cls(messages=messages)
|
||||||
self._restructure_from_openai_messages()
|
self._restructure_from_openai_messages()
|
||||||
return self
|
return self
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_image_frame(cls, frame: VisionImageRawFrame) -> "AWSBedrockLLMContext":
|
def from_image_frame(cls, frame: VisionImageRawFrame) -> "AWSBedrockLLMContext":
|
||||||
|
"""Create AWS Bedrock context from vision image frame.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
frame: The vision image frame to convert.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
New AWS Bedrock LLM context instance.
|
||||||
|
"""
|
||||||
context = cls()
|
context = cls()
|
||||||
context.add_image_frame_message(
|
context.add_image_frame_message(
|
||||||
format=frame.format, size=frame.size, image=frame.image, text=frame.text
|
format=frame.format, size=frame.size, image=frame.image, text=frame.text
|
||||||
@@ -119,10 +191,14 @@ class AWSBedrockLLMContext(OpenAILLMContext):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
def set_messages(self, messages: List):
|
def set_messages(self, messages: List):
|
||||||
|
"""Set the messages list and restructure for Bedrock format.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
messages: List of messages to set.
|
||||||
|
"""
|
||||||
self._messages[:] = messages
|
self._messages[:] = messages
|
||||||
self._restructure_from_openai_messages()
|
self._restructure_from_openai_messages()
|
||||||
|
|
||||||
# convert a message in AWS Bedrock format into one or more messages in OpenAI format
|
|
||||||
def to_standard_messages(self, obj):
|
def to_standard_messages(self, obj):
|
||||||
"""Convert AWS Bedrock message format to standard structured format.
|
"""Convert AWS Bedrock message format to standard structured format.
|
||||||
|
|
||||||
@@ -295,6 +371,14 @@ class AWSBedrockLLMContext(OpenAILLMContext):
|
|||||||
def add_image_frame_message(
|
def add_image_frame_message(
|
||||||
self, *, format: str, size: tuple[int, int], image: bytes, text: str = None
|
self, *, format: str, size: tuple[int, int], image: bytes, text: str = None
|
||||||
):
|
):
|
||||||
|
"""Add an image message to the context.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
format: The image format (e.g., 'RGB', 'RGBA').
|
||||||
|
size: The image dimensions as (width, height).
|
||||||
|
image: The raw image data as bytes.
|
||||||
|
text: Optional text to accompany the image.
|
||||||
|
"""
|
||||||
buffer = io.BytesIO()
|
buffer = io.BytesIO()
|
||||||
Image.frombytes(format, size, image).save(buffer, format="JPEG")
|
Image.frombytes(format, size, image).save(buffer, format="JPEG")
|
||||||
encoded_image = base64.b64encode(buffer.getvalue()).decode("utf-8")
|
encoded_image = base64.b64encode(buffer.getvalue()).decode("utf-8")
|
||||||
@@ -306,6 +390,14 @@ class AWSBedrockLLMContext(OpenAILLMContext):
|
|||||||
self.add_message({"role": "user", "content": content})
|
self.add_message({"role": "user", "content": content})
|
||||||
|
|
||||||
def add_message(self, message):
|
def add_message(self, message):
|
||||||
|
"""Add a message to the context, merging with previous message if same role.
|
||||||
|
|
||||||
|
AWS Bedrock requires alternating roles, so consecutive messages from the
|
||||||
|
same role are merged together.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
message: The message to add to the context.
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
if self.messages:
|
if self.messages:
|
||||||
# AWS Bedrock requires that roles alternate. If this message's
|
# AWS Bedrock requires that roles alternate. If this message's
|
||||||
@@ -330,10 +422,10 @@ class AWSBedrockLLMContext(OpenAILLMContext):
|
|||||||
logger.error(f"Error adding message: {e}")
|
logger.error(f"Error adding message: {e}")
|
||||||
|
|
||||||
def _restructure_from_bedrock_messages(self):
|
def _restructure_from_bedrock_messages(self):
|
||||||
"""Restructure messages in AWS Bedrock format by handling system
|
"""Restructure messages in AWS Bedrock format.
|
||||||
messages, merging consecutive messages with the same role, and ensuring
|
|
||||||
proper content formatting.
|
|
||||||
|
|
||||||
|
Handles system messages, merging consecutive messages with the same role,
|
||||||
|
and ensuring proper content formatting.
|
||||||
"""
|
"""
|
||||||
# Handle system message if present at the beginning
|
# Handle system message if present at the beginning
|
||||||
if self.messages and self.messages[0]["role"] == "system":
|
if self.messages and self.messages[0]["role"] == "system":
|
||||||
@@ -416,12 +508,22 @@ class AWSBedrockLLMContext(OpenAILLMContext):
|
|||||||
message["content"] = [{"type": "text", "text": "(empty)"}]
|
message["content"] = [{"type": "text", "text": "(empty)"}]
|
||||||
|
|
||||||
def get_messages_for_persistent_storage(self):
|
def get_messages_for_persistent_storage(self):
|
||||||
|
"""Get messages formatted for persistent storage.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List of messages including system message if present.
|
||||||
|
"""
|
||||||
messages = super().get_messages_for_persistent_storage()
|
messages = super().get_messages_for_persistent_storage()
|
||||||
if self.system:
|
if self.system:
|
||||||
messages.insert(0, {"role": "system", "content": self.system})
|
messages.insert(0, {"role": "system", "content": self.system})
|
||||||
return messages
|
return messages
|
||||||
|
|
||||||
def get_messages_for_logging(self) -> str:
|
def get_messages_for_logging(self) -> str:
|
||||||
|
"""Get messages formatted for logging with sensitive data redacted.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
JSON string representation of messages with image data redacted.
|
||||||
|
"""
|
||||||
msgs = []
|
msgs = []
|
||||||
for message in self.messages:
|
for message in self.messages:
|
||||||
msg = copy.deepcopy(message)
|
msg = copy.deepcopy(message)
|
||||||
@@ -435,11 +537,36 @@ class AWSBedrockLLMContext(OpenAILLMContext):
|
|||||||
|
|
||||||
|
|
||||||
class AWSBedrockUserContextAggregator(LLMUserContextAggregator):
|
class AWSBedrockUserContextAggregator(LLMUserContextAggregator):
|
||||||
|
"""User context aggregator for AWS Bedrock LLM service.
|
||||||
|
|
||||||
|
Handles aggregation of user messages and frames for AWS Bedrock format.
|
||||||
|
Inherits all functionality from the base LLM user context aggregator.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
context: The LLM context to aggregate messages into.
|
||||||
|
params: Configuration parameters for the aggregator.
|
||||||
|
"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class AWSBedrockAssistantContextAggregator(LLMAssistantContextAggregator):
|
class AWSBedrockAssistantContextAggregator(LLMAssistantContextAggregator):
|
||||||
|
"""Assistant context aggregator for AWS Bedrock LLM service.
|
||||||
|
|
||||||
|
Handles aggregation of assistant responses and function calls for AWS Bedrock
|
||||||
|
format, including tool use and tool result handling.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
context: The LLM context to aggregate messages into.
|
||||||
|
params: Configuration parameters for the aggregator.
|
||||||
|
"""
|
||||||
|
|
||||||
async def handle_function_call_in_progress(self, frame: FunctionCallInProgressFrame):
|
async def handle_function_call_in_progress(self, frame: FunctionCallInProgressFrame):
|
||||||
|
"""Handle function call in progress frame.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
frame: The function call in progress frame to handle.
|
||||||
|
"""
|
||||||
# Format tool use according to AWS Bedrock API
|
# Format tool use according to AWS Bedrock API
|
||||||
self._context.add_message(
|
self._context.add_message(
|
||||||
{
|
{
|
||||||
@@ -470,6 +597,11 @@ class AWSBedrockAssistantContextAggregator(LLMAssistantContextAggregator):
|
|||||||
)
|
)
|
||||||
|
|
||||||
async def handle_function_call_result(self, frame: FunctionCallResultFrame):
|
async def handle_function_call_result(self, frame: FunctionCallResultFrame):
|
||||||
|
"""Handle function call result frame.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
frame: The function call result frame to handle.
|
||||||
|
"""
|
||||||
if frame.result:
|
if frame.result:
|
||||||
result = json.dumps(frame.result)
|
result = json.dumps(frame.result)
|
||||||
await self._update_function_call_result(frame.function_name, frame.tool_call_id, result)
|
await self._update_function_call_result(frame.function_name, frame.tool_call_id, result)
|
||||||
@@ -479,6 +611,11 @@ class AWSBedrockAssistantContextAggregator(LLMAssistantContextAggregator):
|
|||||||
)
|
)
|
||||||
|
|
||||||
async def handle_function_call_cancel(self, frame: FunctionCallCancelFrame):
|
async def handle_function_call_cancel(self, frame: FunctionCallCancelFrame):
|
||||||
|
"""Handle function call cancel frame.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
frame: The function call cancel frame to handle.
|
||||||
|
"""
|
||||||
await self._update_function_call_result(
|
await self._update_function_call_result(
|
||||||
frame.function_name, frame.tool_call_id, "CANCELLED"
|
frame.function_name, frame.tool_call_id, "CANCELLED"
|
||||||
)
|
)
|
||||||
@@ -497,6 +634,11 @@ class AWSBedrockAssistantContextAggregator(LLMAssistantContextAggregator):
|
|||||||
content["toolResult"]["content"] = [{"text": result}]
|
content["toolResult"]["content"] = [{"text": result}]
|
||||||
|
|
||||||
async def handle_user_image_frame(self, frame: UserImageRawFrame):
|
async def handle_user_image_frame(self, frame: UserImageRawFrame):
|
||||||
|
"""Handle user image frame.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
frame: The user image frame to handle.
|
||||||
|
"""
|
||||||
await self._update_function_call_result(
|
await self._update_function_call_result(
|
||||||
frame.request.function_name, frame.request.tool_call_id, "COMPLETED"
|
frame.request.function_name, frame.request.tool_call_id, "COMPLETED"
|
||||||
)
|
)
|
||||||
@@ -509,18 +651,38 @@ class AWSBedrockAssistantContextAggregator(LLMAssistantContextAggregator):
|
|||||||
|
|
||||||
|
|
||||||
class AWSBedrockLLMService(LLMService):
|
class AWSBedrockLLMService(LLMService):
|
||||||
"""This class implements inference with AWS Bedrock models including Amazon
|
"""AWS Bedrock Large Language Model service implementation.
|
||||||
Nova and Anthropic Claude.
|
|
||||||
|
|
||||||
Requires AWS credentials to be configured in the environment or through
|
Provides inference capabilities for AWS Bedrock models including Amazon Nova
|
||||||
boto3 configuration.
|
and Anthropic Claude. Supports streaming responses, function calling, and
|
||||||
|
vision capabilities.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
model: The AWS Bedrock model identifier to use.
|
||||||
|
aws_access_key: AWS access key ID. If None, uses default credentials.
|
||||||
|
aws_secret_key: AWS secret access key. If None, uses default credentials.
|
||||||
|
aws_session_token: AWS session token for temporary credentials.
|
||||||
|
aws_region: AWS region for the Bedrock service.
|
||||||
|
params: Model parameters and configuration.
|
||||||
|
client_config: Custom boto3 client configuration.
|
||||||
|
**kwargs: Additional arguments passed to parent LLMService.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Overriding the default adapter to use the Anthropic one.
|
# Overriding the default adapter to use the Anthropic one.
|
||||||
adapter_class = AWSBedrockLLMAdapter
|
adapter_class = AWSBedrockLLMAdapter
|
||||||
|
|
||||||
class InputParams(BaseModel):
|
class InputParams(BaseModel):
|
||||||
|
"""Input parameters for AWS Bedrock LLM service.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
max_tokens: Maximum number of tokens to generate.
|
||||||
|
temperature: Sampling temperature between 0.0 and 1.0.
|
||||||
|
top_p: Nucleus sampling parameter between 0.0 and 1.0.
|
||||||
|
stop_sequences: List of strings that stop generation.
|
||||||
|
latency: Performance mode - "standard" or "optimized".
|
||||||
|
additional_model_request_fields: Additional model-specific parameters.
|
||||||
|
"""
|
||||||
|
|
||||||
max_tokens: Optional[int] = Field(default_factory=lambda: 4096, ge=1)
|
max_tokens: Optional[int] = Field(default_factory=lambda: 4096, ge=1)
|
||||||
temperature: Optional[float] = Field(default_factory=lambda: 0.7, ge=0.0, le=1.0)
|
temperature: Optional[float] = Field(default_factory=lambda: 0.7, ge=0.0, le=1.0)
|
||||||
top_p: Optional[float] = Field(default_factory=lambda: 0.999, ge=0.0, le=1.0)
|
top_p: Optional[float] = Field(default_factory=lambda: 0.999, ge=0.0, le=1.0)
|
||||||
@@ -573,6 +735,11 @@ class AWSBedrockLLMService(LLMService):
|
|||||||
logger.info(f"Using AWS Bedrock model: {model}")
|
logger.info(f"Using AWS Bedrock model: {model}")
|
||||||
|
|
||||||
def can_generate_metrics(self) -> bool:
|
def can_generate_metrics(self) -> bool:
|
||||||
|
"""Check if the service can generate usage metrics.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True if metrics generation is supported.
|
||||||
|
"""
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def create_context_aggregator(
|
def create_context_aggregator(
|
||||||
@@ -582,21 +749,21 @@ class AWSBedrockLLMService(LLMService):
|
|||||||
user_params: LLMUserAggregatorParams = LLMUserAggregatorParams(),
|
user_params: LLMUserAggregatorParams = LLMUserAggregatorParams(),
|
||||||
assistant_params: LLMAssistantAggregatorParams = LLMAssistantAggregatorParams(),
|
assistant_params: LLMAssistantAggregatorParams = LLMAssistantAggregatorParams(),
|
||||||
) -> AWSBedrockContextAggregatorPair:
|
) -> AWSBedrockContextAggregatorPair:
|
||||||
"""Create an instance of AWSBedrockContextAggregatorPair from an
|
"""Create AWS Bedrock-specific context aggregators.
|
||||||
OpenAILLMContext. Constructor keyword arguments for both the user and
|
|
||||||
assistant aggregators can be provided.
|
Creates a pair of context aggregators optimized for AWS Bedrocks's message
|
||||||
|
format, including support for function calls, tool usage, and image handling.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
context (OpenAILLMContext): The LLM context.
|
context: The LLM context to create aggregators for.
|
||||||
user_params (LLMUserAggregatorParams, optional): User aggregator
|
user_params: Parameters for user message aggregation.
|
||||||
parameters.
|
assistant_params: Parameters for assistant message aggregation.
|
||||||
assistant_params (LLMAssistantAggregatorParams, optional): User
|
|
||||||
aggregator parameters.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
AWSBedrockContextAggregatorPair: A pair of context aggregators, one
|
AWSBedrockContextAggregatorPair: A pair of context aggregators, one for
|
||||||
for the user and one for the assistant, encapsulated in an
|
the user and one for the assistant, encapsulated in an
|
||||||
AWSBedrockContextAggregatorPair.
|
AWSBedrockContextAggregatorPair.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
context.set_llm_adapter(self.get_llm_adapter())
|
context.set_llm_adapter(self.get_llm_adapter())
|
||||||
|
|
||||||
@@ -792,6 +959,12 @@ class AWSBedrockLLMService(LLMService):
|
|||||||
)
|
)
|
||||||
|
|
||||||
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
||||||
|
"""Process incoming frames and handle LLM-specific frame types.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
frame: The frame to process.
|
||||||
|
direction: The direction of frame processing.
|
||||||
|
"""
|
||||||
await super().process_frame(frame, direction)
|
await super().process_frame(frame, direction)
|
||||||
|
|
||||||
context = None
|
context = None
|
||||||
|
|||||||
Reference in New Issue
Block a user