chore: import upstream snapshot with attribution
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:21:23 +08:00
commit b957a53def
5423 changed files with 863745 additions and 0 deletions
@@ -0,0 +1,187 @@
# Copyright (c) Microsoft. All rights reserved.
from collections.abc import Callable
import pytest
from semantic_kernel.agents.bedrock.models.bedrock_agent_event_type import BedrockAgentEventType
from semantic_kernel.agents.bedrock.models.bedrock_agent_model import BedrockAgentModel
from semantic_kernel.agents.bedrock.models.bedrock_agent_status import BedrockAgentStatus
from semantic_kernel.kernel import Kernel
@pytest.fixture()
def bedrock_agent_unit_test_env(monkeypatch, exclude_list, override_env_param_dict):
"""Fixture to set environment variables for Amazon Bedrock Agent unit tests."""
if exclude_list is None:
exclude_list = []
if override_env_param_dict is None:
override_env_param_dict = {}
env_vars = {
"BEDROCK_AGENT_AGENT_RESOURCE_ROLE_ARN": "TEST_BEDROCK_AGENT_AGENT_RESOURCE_ROLE_ARN",
"BEDROCK_AGENT_FOUNDATION_MODEL": "TEST_BEDROCK_AGENT_FOUNDATION_MODEL",
}
env_vars.update(override_env_param_dict)
for key, value in env_vars.items():
if key not in exclude_list:
monkeypatch.setenv(key, value)
else:
monkeypatch.delenv(key, raising=False)
return env_vars
@pytest.fixture
def kernel_with_function(kernel: Kernel, decorated_native_function: Callable) -> Kernel:
kernel.add_function("test_plugin", function=decorated_native_function)
return kernel
@pytest.fixture
def new_agent_name():
return "test_agent_name"
@pytest.fixture
def bedrock_agent_model():
return BedrockAgentModel(
agent_name="test_agent_name",
foundation_model="test_foundation_model",
agent_status=BedrockAgentStatus.NOT_PREPARED,
)
@pytest.fixture
def bedrock_agent_model_with_id():
return BedrockAgentModel(
agent_id="test_agent_id",
agent_name="test_agent_name",
foundation_model="test_foundation_model",
agent_status=BedrockAgentStatus.NOT_PREPARED,
)
@pytest.fixture
def bedrock_agent_model_with_id_prepared_dict():
return {
"agent": {
"agentId": "test_agent_id",
"agentName": "test_agent_name",
"foundationModel": "test_foundation_model",
"agentStatus": "PREPARED",
}
}
@pytest.fixture
def bedrock_agent_model_with_id_preparing_dict():
return {
"agent": {
"agentId": "test_agent_id",
"agentName": "test_agent_name",
"foundationModel": "test_foundation_model",
"agentStatus": "PREPARING",
}
}
@pytest.fixture
def bedrock_agent_model_with_id_not_prepared_dict():
return {
"agent": {
"agentId": "test_agent_id",
"agentName": "test_agent_name",
"foundationModel": "test_foundation_model",
"agentStatus": "NOT_PREPARED",
}
}
@pytest.fixture
def existing_agent_not_prepared_model():
return BedrockAgentModel(
agent_id="test_agent_id",
agent_name="test_agent_name",
foundation_model="test_foundation_model",
agent_status=BedrockAgentStatus.NOT_PREPARED,
)
@pytest.fixture
def bedrock_action_group_mode_dict():
return {
"agentActionGroup": {
"actionGroupId": "test_action_group_id",
"actionGroupName": "test_action_group_name",
}
}
@pytest.fixture
def simple_response():
return "test response"
@pytest.fixture
def bedrock_agent_non_streaming_empty_response():
return {
"completion": [],
}
@pytest.fixture
def bedrock_agent_non_streaming_simple_response(simple_response):
return {
"completion": [
{
"chunk": {"bytes": bytes(simple_response, "utf-8")},
},
],
}
@pytest.fixture
def bedrock_agent_streaming_simple_response(simple_response):
return {
"completion": [
{
"chunk": {"bytes": bytes(chunk, "utf-8")},
}
for chunk in simple_response
]
}
@pytest.fixture
def bedrock_agent_function_call_response():
return {
"completion": [
{
BedrockAgentEventType.RETURN_CONTROL: {
"invocationId": "test_invocation_id",
"invocationInputs": [
{
"functionInvocationInput": {
"function": "test_function",
"parameters": [
{"name": "test_parameter_name", "value": "test_parameter_value"},
],
},
},
],
},
},
],
}
@pytest.fixture
def bedrock_agent_create_session_response():
return {
"sessionId": "test_session_id",
}
@@ -0,0 +1,93 @@
# Copyright (c) Microsoft. All rights reserved.
import pytest
from semantic_kernel.agents.bedrock.action_group_utils import (
BEDROCK_FUNCTION_ALLOWED_PARAMETER_TYPES,
kernel_function_parameter_type_to_bedrock_function_parameter_type,
kernel_function_to_bedrock_function_schema,
parse_function_result_contents,
parse_return_control_payload,
)
from semantic_kernel.connectors.ai.function_choice_behavior import FunctionChoiceBehavior
from semantic_kernel.contents.function_result_content import FunctionResultContent
from semantic_kernel.kernel import Kernel
def test_kernel_function_to_bedrock_function_schema(kernel_with_function: Kernel):
# Test the conversion of kernel function to bedrock function schema
function_choice_behavior = FunctionChoiceBehavior.Auto()
function_choice_configuration = function_choice_behavior.get_config(kernel_with_function)
result = kernel_function_to_bedrock_function_schema(function_choice_configuration)
assert result == {
"functions": [
{
"name": "test_plugin-getLightStatus",
"parameters": {
"arg1": {
"type": "string",
"required": True,
}
},
"requireConfirmation": "DISABLED",
}
]
}
def test_kernel_function_parameter_type_to_bedrock_function_parameter_type():
# Test the conversion of kernel function parameter type to bedrock function parameter type
schema_data = {"type": "string"}
result = kernel_function_parameter_type_to_bedrock_function_parameter_type(schema_data)
assert result == "string"
def test_kernel_function_parameter_type_to_bedrock_function_parameter_type_invalid():
# Test the conversion of invalid kernel function parameter type to bedrock function parameter type
schema_data = {"type": "invalid_type"}
with pytest.raises(
ValueError,
match="Type invalid_type is not allowed in bedrock function parameter type. "
f"Allowed types are {BEDROCK_FUNCTION_ALLOWED_PARAMETER_TYPES}.",
):
kernel_function_parameter_type_to_bedrock_function_parameter_type(schema_data)
def test_parse_return_control_payload():
# Test the parsing of return control payload to function call contents
return_control_payload = {
"invocationId": "test_invocation_id",
"invocationInputs": [
{
"functionInvocationInput": {
"function": "test_function",
"parameters": [
{"name": "param1", "value": "value1"},
{"name": "param2", "value": "value2"},
],
}
}
],
}
result = parse_return_control_payload(return_control_payload)
assert len(result) == 1
assert result[0].id == "test_invocation_id"
assert result[0].name == "test_function"
assert result[0].arguments == {"param1": "value1", "param2": "value2"}
def test_parse_function_result_contents():
# Test the parsing of function result contents to be returned to the agent
function_result_contents = [
FunctionResultContent(
id="test_id",
name="test_function",
result="test_result",
metadata={"functionInvocationInput": {"actionGroup": "test_action_group"}},
)
]
result = parse_function_result_contents(function_result_contents)
assert len(result) == 1
assert result[0]["functionResult"]["actionGroup"] == "test_action_group"
assert result[0]["functionResult"]["function"] == "test_function"
assert result[0]["functionResult"]["responseBody"]["TEXT"]["body"] == "test_result"
@@ -0,0 +1,33 @@
# Copyright (c) Microsoft. All rights reserved.
import pytest
from pydantic import ValidationError
from semantic_kernel.agents.bedrock.models.bedrock_action_group_model import BedrockActionGroupModel
def test_bedrock_action_group_model_valid():
"""Test case to verify the BedrockActionGroupModel with valid data."""
model = BedrockActionGroupModel(actionGroupId="test_id", actionGroupName="test_name")
assert model.action_group_id == "test_id"
assert model.action_group_name == "test_name"
def test_bedrock_action_group_model_missing_action_group_id():
"""Test case to verify error handling when actionGroupId is missing."""
with pytest.raises(ValidationError):
BedrockActionGroupModel(actionGroupName="test_name")
def test_bedrock_action_group_model_missing_action_group_name():
"""Test case to verify error handling when actionGroupName is missing."""
with pytest.raises(ValidationError):
BedrockActionGroupModel(actionGroupId="test_id")
def test_bedrock_action_group_model_extra_field():
"""Test case to verify the BedrockActionGroupModel with an extra field."""
model = BedrockActionGroupModel(actionGroupId="test_id", actionGroupName="test_name", extraField="extra_value")
assert model.action_group_id == "test_id"
assert model.action_group_name == "test_name"
assert model.extraField == "extra_value"
@@ -0,0 +1,751 @@
# Copyright (c) Microsoft. All rights reserved.
from unittest.mock import AsyncMock, Mock, PropertyMock, patch
import boto3
import pytest
from semantic_kernel.agents.bedrock.action_group_utils import (
kernel_function_to_bedrock_function_schema,
parse_function_result_contents,
)
from semantic_kernel.agents.bedrock.bedrock_agent import BedrockAgent, BedrockAgentThread
from semantic_kernel.connectors.ai.function_choice_behavior import FunctionChoiceBehavior
from semantic_kernel.contents.function_result_content import FunctionResultContent
from semantic_kernel.exceptions.agent_exceptions import AgentInitializationException, AgentInvokeException
from semantic_kernel.functions.kernel_arguments import KernelArguments
from semantic_kernel.kernel import Kernel
# region Agent Initialization Tests
# Test case to verify BedrockAgent initialization
@patch.object(boto3, "client", return_value=Mock())
async def test_bedrock_agent_initialization(client, bedrock_agent_model_with_id):
agent = BedrockAgent(bedrock_agent_model_with_id)
assert agent.name == bedrock_agent_model_with_id.agent_name
assert agent.agent_model.agent_name == bedrock_agent_model_with_id.agent_name
assert agent.agent_model.agent_id == bedrock_agent_model_with_id.agent_id
assert agent.agent_model.foundation_model == bedrock_agent_model_with_id.foundation_model
# Test case to verify error handling during BedrockAgent initialization with non-auto function choice
@patch.object(boto3, "client", return_value=Mock())
async def test_bedrock_agent_initialization_error_with_non_auto_function_choice(client, bedrock_agent_model_with_id):
with pytest.raises(ValueError, match="Only FunctionChoiceType.AUTO is supported."):
BedrockAgent(
bedrock_agent_model_with_id,
function_choice_behavior=FunctionChoiceBehavior.NoneInvoke(),
)
# Test case to verify the creation of BedrockAgent
@patch.object(boto3, "client", return_value=Mock())
@pytest.mark.parametrize(
"kernel, function_choice_behavior, arguments",
[
(None, None, None),
(Kernel(), None, None),
(Kernel(), FunctionChoiceBehavior.Auto(), None),
(Kernel(), FunctionChoiceBehavior.Auto(), KernelArguments()),
],
)
async def test_bedrock_agent_create_and_prepare_agent(
client,
bedrock_agent_model_with_id_not_prepared_dict,
bedrock_agent_unit_test_env,
kernel,
function_choice_behavior,
arguments,
):
with (
patch.object(client, "create_agent") as mock_create_agent,
patch.object(BedrockAgent, "_wait_for_agent_status", new_callable=AsyncMock),
patch.object(BedrockAgent, "prepare_agent_and_wait_until_prepared", new_callable=AsyncMock),
):
mock_create_agent.return_value = bedrock_agent_model_with_id_not_prepared_dict
agent = await BedrockAgent.create_and_prepare_agent(
name=bedrock_agent_model_with_id_not_prepared_dict["agent"]["agentName"],
instructions="test_instructions",
bedrock_client=client,
env_file_path="fake_path",
kernel=kernel,
function_choice_behavior=function_choice_behavior,
arguments=arguments,
)
mock_create_agent.assert_called_once_with(
agentName=bedrock_agent_model_with_id_not_prepared_dict["agent"]["agentName"],
foundationModel=bedrock_agent_unit_test_env["BEDROCK_AGENT_FOUNDATION_MODEL"],
agentResourceRoleArn=bedrock_agent_unit_test_env["BEDROCK_AGENT_AGENT_RESOURCE_ROLE_ARN"],
instruction="test_instructions",
)
assert agent.agent_model.agent_id == bedrock_agent_model_with_id_not_prepared_dict["agent"]["agentId"]
assert agent.id == bedrock_agent_model_with_id_not_prepared_dict["agent"]["agentId"]
assert agent.agent_model.agent_name == bedrock_agent_model_with_id_not_prepared_dict["agent"]["agentName"]
assert agent.name == bedrock_agent_model_with_id_not_prepared_dict["agent"]["agentName"]
assert (
agent.agent_model.foundation_model
== bedrock_agent_model_with_id_not_prepared_dict["agent"]["foundationModel"]
)
assert agent.kernel is not None
assert agent.function_choice_behavior is not None
if arguments:
assert agent.arguments is not None
# Test case to verify the creation of BedrockAgent
@pytest.mark.parametrize(
"exclude_list",
[
["BEDROCK_AGENT_AGENT_RESOURCE_ROLE_ARN"],
["BEDROCK_AGENT_FOUNDATION_MODEL"],
],
indirect=True,
)
@patch.object(boto3, "client", return_value=Mock())
async def test_bedrock_agent_create_and_prepare_agent_settings_validation_error(
client,
bedrock_agent_model_with_id_not_prepared_dict,
bedrock_agent_unit_test_env,
):
with pytest.raises(AgentInitializationException):
await BedrockAgent.create_and_prepare_agent(
name=bedrock_agent_model_with_id_not_prepared_dict["agent"]["agentName"],
instructions="test_instructions",
env_file_path="fake_path",
)
# Test case to verify the creation of BedrockAgent
@patch.object(boto3, "client", return_value=Mock())
async def test_bedrock_agent_create_and_prepare_agent_service_exception(
client,
bedrock_agent_model_with_id_not_prepared_dict,
bedrock_agent_unit_test_env,
):
with (
patch.object(client, "create_agent") as mock_create_agent,
patch.object(BedrockAgent, "prepare_agent_and_wait_until_prepared", new_callable=AsyncMock),
):
from botocore.exceptions import ClientError
mock_create_agent.side_effect = ClientError({}, "create_agent")
with pytest.raises(AgentInitializationException):
await BedrockAgent.create_and_prepare_agent(
name=bedrock_agent_model_with_id_not_prepared_dict["agent"]["agentName"],
instructions="test_instructions",
bedrock_client=client,
env_file_path="fake_path",
)
@patch.object(boto3, "client", return_value=Mock())
async def test_bedrock_agent_prepare_agent_and_wait_until_prepared(
client,
bedrock_agent_unit_test_env,
bedrock_agent_model_with_id,
bedrock_agent_model_with_id_preparing_dict,
bedrock_agent_model_with_id_prepared_dict,
):
agent = BedrockAgent(bedrock_agent_model_with_id, bedrock_client=client)
with (
patch.object(client, "get_agent") as mock_get_agent,
patch.object(client, "prepare_agent") as mock_prepare_agent,
):
mock_get_agent.side_effect = [
bedrock_agent_model_with_id_preparing_dict,
bedrock_agent_model_with_id_prepared_dict,
]
await agent.prepare_agent_and_wait_until_prepared()
mock_prepare_agent.assert_called_once_with(agentId=bedrock_agent_model_with_id.agent_id)
assert mock_get_agent.call_count == 2
assert agent.agent_model.agent_status == "PREPARED"
@patch.object(boto3, "client", return_value=Mock())
async def test_bedrock_agent_prepare_agent_and_wait_until_prepared_fail(
client,
bedrock_agent_unit_test_env,
bedrock_agent_model_with_id,
bedrock_agent_model_with_id_preparing_dict,
):
agent = BedrockAgent(bedrock_agent_model_with_id, bedrock_client=client)
with (
patch.object(client, "get_agent") as mock_get_agent,
patch.object(client, "prepare_agent"),
):
mock_get_agent.side_effect = [
bedrock_agent_model_with_id_preparing_dict,
bedrock_agent_model_with_id_preparing_dict,
bedrock_agent_model_with_id_preparing_dict,
bedrock_agent_model_with_id_preparing_dict,
bedrock_agent_model_with_id_preparing_dict,
bedrock_agent_model_with_id_preparing_dict,
]
with pytest.raises(TimeoutError):
await agent.prepare_agent_and_wait_until_prepared()
# Test case to verify the creation of a code interpreter action group
@patch.object(boto3, "client", return_value=Mock())
async def test_create_code_interpreter_action_group(
client,
bedrock_agent_unit_test_env,
bedrock_agent_model_with_id,
bedrock_action_group_mode_dict,
):
agent = BedrockAgent(bedrock_agent_model_with_id, bedrock_client=client)
with (
patch.object(client, "create_agent_action_group") as mock_create_action_group,
patch.object(
BedrockAgent, "prepare_agent_and_wait_until_prepared"
) as mock_prepare_agent_and_wait_until_prepared,
):
mock_create_action_group.return_value = bedrock_action_group_mode_dict
action_group_model = await agent.create_code_interpreter_action_group()
mock_create_action_group.assert_called_once_with(
agentId=agent.agent_model.agent_id,
agentVersion=agent.agent_model.agent_version or "DRAFT",
actionGroupName=f"{agent.agent_model.agent_name}_code_interpreter",
actionGroupState="ENABLED",
parentActionGroupSignature="AMAZON.CodeInterpreter",
)
assert action_group_model.action_group_id == bedrock_action_group_mode_dict["agentActionGroup"]["actionGroupId"]
mock_prepare_agent_and_wait_until_prepared.assert_called_once()
# Test case to verify the creation of BedrockAgent with plugins
@patch.object(boto3, "client", return_value=Mock())
async def test_bedrock_agent_create_with_plugin_via_constructor(
client,
bedrock_agent_unit_test_env,
bedrock_agent_model_with_id,
custom_plugin_class,
):
agent = BedrockAgent(
bedrock_agent_model_with_id,
plugins=[custom_plugin_class()],
bedrock_client=client,
)
assert agent.kernel.plugins is not None
assert len(agent.kernel.plugins) == 1
# Test case to verify the creation of a user input action group
@patch.object(boto3, "client", return_value=Mock())
async def test_create_user_input_action_group(
client,
bedrock_agent_unit_test_env,
bedrock_agent_model_with_id,
bedrock_action_group_mode_dict,
):
agent = BedrockAgent(bedrock_agent_model_with_id, bedrock_client=client)
with (
patch.object(agent.bedrock_client, "create_agent_action_group") as mock_create_action_group,
patch.object(
BedrockAgent, "prepare_agent_and_wait_until_prepared"
) as mock_prepare_agent_and_wait_until_prepared,
):
mock_create_action_group.return_value = bedrock_action_group_mode_dict
action_group_model = await agent.create_user_input_action_group()
mock_create_action_group.assert_called_once_with(
agentId=agent.agent_model.agent_id,
agentVersion=agent.agent_model.agent_version or "DRAFT",
actionGroupName=f"{agent.agent_model.agent_name}_user_input",
actionGroupState="ENABLED",
parentActionGroupSignature="AMAZON.UserInput",
)
assert action_group_model.action_group_id == bedrock_action_group_mode_dict["agentActionGroup"]["actionGroupId"]
mock_prepare_agent_and_wait_until_prepared.assert_called_once()
# Test case to verify the creation of a kernel function action group
@patch.object(boto3, "client", return_value=Mock())
async def test_create_kernel_function_action_group(
client,
kernel_with_function,
bedrock_agent_unit_test_env,
bedrock_agent_model_with_id,
bedrock_action_group_mode_dict,
):
agent = BedrockAgent(bedrock_agent_model_with_id, kernel=kernel_with_function, bedrock_client=client)
with (
patch.object(agent.bedrock_client, "create_agent_action_group") as mock_create_action_group,
patch.object(
BedrockAgent, "prepare_agent_and_wait_until_prepared"
) as mock_prepare_agent_and_wait_until_prepared,
):
mock_create_action_group.return_value = bedrock_action_group_mode_dict
action_group_model = await agent.create_kernel_function_action_group()
mock_create_action_group.assert_called_once_with(
agentId=agent.agent_model.agent_id,
agentVersion=agent.agent_model.agent_version or "DRAFT",
actionGroupName=f"{agent.agent_model.agent_name}_kernel_function",
actionGroupState="ENABLED",
actionGroupExecutor={"customControl": "RETURN_CONTROL"},
functionSchema=kernel_function_to_bedrock_function_schema(
agent.function_choice_behavior.get_config(kernel_with_function)
),
)
assert action_group_model.action_group_id == bedrock_action_group_mode_dict["agentActionGroup"]["actionGroupId"]
mock_prepare_agent_and_wait_until_prepared.assert_called_once()
# Test case to verify the association of an agent with a knowledge base
@patch.object(boto3, "client", return_value=Mock())
async def test_associate_agent_knowledge_base(
client,
bedrock_agent_unit_test_env,
bedrock_agent_model_with_id,
):
agent = BedrockAgent(bedrock_agent_model_with_id, bedrock_client=client)
with (
patch.object(agent.bedrock_client, "associate_agent_knowledge_base") as mock_associate_knowledge_base,
patch.object(
BedrockAgent, "prepare_agent_and_wait_until_prepared"
) as mock_prepare_agent_and_wait_until_prepared,
):
await agent.associate_agent_knowledge_base("test_knowledge_base_id")
mock_associate_knowledge_base.assert_called_once_with(
agentId=agent.agent_model.agent_id,
agentVersion=agent.agent_model.agent_version,
knowledgeBaseId="test_knowledge_base_id",
)
mock_prepare_agent_and_wait_until_prepared.assert_called_once()
# Test case to verify the disassociation of an agent with a knowledge base
@patch.object(boto3, "client", return_value=Mock())
async def test_disassociate_agent_knowledge_base(
client,
bedrock_agent_unit_test_env,
bedrock_agent_model_with_id,
):
agent = BedrockAgent(bedrock_agent_model_with_id, bedrock_client=client)
with (
patch.object(agent.bedrock_client, "disassociate_agent_knowledge_base") as mock_disassociate_knowledge_base,
patch.object(
BedrockAgent, "prepare_agent_and_wait_until_prepared"
) as mock_prepare_agent_and_wait_until_prepared,
):
await agent.disassociate_agent_knowledge_base("test_knowledge_base_id")
mock_disassociate_knowledge_base.assert_called_once_with(
agentId=agent.agent_model.agent_id,
agentVersion=agent.agent_model.agent_version,
knowledgeBaseId="test_knowledge_base_id",
)
mock_prepare_agent_and_wait_until_prepared.assert_called_once()
# Test case to verify listing associated knowledge bases with an agent
@patch.object(boto3, "client", return_value=Mock())
async def test_list_associated_agent_knowledge_bases(
client,
bedrock_agent_unit_test_env,
bedrock_agent_model_with_id,
):
agent = BedrockAgent(bedrock_agent_model_with_id, bedrock_client=client)
with patch.object(agent.bedrock_client, "list_agent_knowledge_bases") as mock_list_knowledge_bases:
await agent.list_associated_agent_knowledge_bases()
mock_list_knowledge_bases.assert_called_once_with(
agentId=agent.agent_model.agent_id,
agentVersion=agent.agent_model.agent_version,
)
# endregion
# region Agent Deletion Tests
@patch.object(boto3, "client", return_value=Mock())
async def test_delete_agent(
client,
bedrock_agent_unit_test_env,
bedrock_agent_model_with_id,
):
agent = BedrockAgent(bedrock_agent_model_with_id, bedrock_client=client)
agent_id = bedrock_agent_model_with_id.agent_id
with patch.object(agent.bedrock_client, "delete_agent") as mock_delete_agent:
await agent.delete_agent()
mock_delete_agent.assert_called_once_with(agentId=agent_id)
assert agent.agent_model.agent_id is None
# Test case to verify error handling when deleting an agent that does not exist
@patch.object(boto3, "client", return_value=Mock())
async def test_delete_agent_twice_error(
client,
bedrock_agent_unit_test_env,
bedrock_agent_model_with_id,
):
agent = BedrockAgent(bedrock_agent_model_with_id, bedrock_client=client)
with patch.object(agent.bedrock_client, "delete_agent"):
await agent.delete_agent()
with pytest.raises(ValueError):
await agent.delete_agent()
# Test case to verify error handling when there is a client error during agent deletion
@patch.object(boto3, "client", return_value=Mock())
async def test_delete_agent_client_error(
client,
bedrock_agent_unit_test_env,
bedrock_agent_model_with_id,
):
agent = BedrockAgent(bedrock_agent_model_with_id, bedrock_client=client)
with patch.object(agent.bedrock_client, "delete_agent") as mock_delete_agent:
from botocore.exceptions import ClientError
mock_delete_agent.side_effect = ClientError({"Error": {"Code": "500"}}, "delete_agent")
with pytest.raises(ClientError):
await agent.delete_agent()
# endregion
# region Agent Invoke Tests
# Test case to verify the `get_response` method of BedrockAgent
@pytest.mark.parametrize(
"thread",
[
None,
BedrockAgentThread(None, session_id="test_session_id"),
],
)
@patch.object(boto3, "client", return_value=Mock())
async def test_bedrock_agent_get_response(
client,
thread,
bedrock_agent_unit_test_env,
bedrock_agent_model_with_id,
bedrock_agent_non_streaming_simple_response,
simple_response,
):
with (
patch.object(BedrockAgent, "_invoke_agent", new_callable=AsyncMock) as mock_invoke_agent,
patch.object(BedrockAgentThread, "create", new_callable=AsyncMock) as mock_start,
patch(
"semantic_kernel.agents.bedrock.bedrock_agent.BedrockAgentThread.id",
new_callable=PropertyMock,
) as mock_id,
):
agent = BedrockAgent(bedrock_agent_model_with_id)
mock_id.return_value = "mock-thread-id"
mock_invoke_agent.return_value = bedrock_agent_non_streaming_simple_response
mock_start.return_value = "test_session_id"
response = await agent.get_response(messages="test_input_text", thread=thread)
assert response.message.content == simple_response
mock_invoke_agent.assert_called_once()
# Test case to verify the `get_response` method of BedrockAgent
@patch.object(boto3, "client", return_value=Mock())
async def test_bedrock_agent_get_response_exception(
client,
bedrock_agent_unit_test_env,
bedrock_agent_model_with_id,
bedrock_agent_non_streaming_empty_response,
):
with (
patch.object(BedrockAgent, "_invoke_agent", new_callable=AsyncMock) as mock_invoke_agent,
patch.object(BedrockAgentThread, "create", new_callable=AsyncMock) as mock_start,
patch(
"semantic_kernel.agents.bedrock.bedrock_agent.BedrockAgentThread.id",
new_callable=PropertyMock,
) as mock_id,
):
agent = BedrockAgent(bedrock_agent_model_with_id)
mock_id.return_value = "mock-thread-id"
mock_invoke_agent.return_value = bedrock_agent_non_streaming_empty_response
mock_start.return_value = "test_session_id"
with pytest.raises(AgentInvokeException):
await agent.get_response(messages="test_input_text")
# Test case to verify the invocation of BedrockAgent
@pytest.mark.parametrize(
"thread",
[
None,
BedrockAgentThread(None, session_id="test_session_id"),
],
)
@patch.object(boto3, "client", return_value=Mock())
async def test_bedrock_agent_invoke(
client,
thread,
bedrock_agent_unit_test_env,
bedrock_agent_model_with_id,
bedrock_agent_non_streaming_simple_response,
simple_response,
):
with (
patch.object(BedrockAgent, "_invoke_agent", new_callable=AsyncMock) as mock_invoke_agent,
patch.object(BedrockAgentThread, "create", new_callable=AsyncMock) as mock_start,
patch.object(BedrockAgentThread, "id", "test_session_id"),
):
agent = BedrockAgent(bedrock_agent_model_with_id)
mock_invoke_agent.return_value = bedrock_agent_non_streaming_simple_response
mock_start.return_value = "test_session_id"
async for response in agent.invoke(messages="test_input_text", thread=thread):
assert response.message.content == simple_response
mock_invoke_agent.assert_called_once_with(
"test_session_id",
"test_input_text",
None,
streamingConfigurations={"streamFinalResponse": False},
sessionState={},
)
# Test case to verify the streaming invocation of BedrockAgent
@pytest.mark.parametrize(
"thread",
[
None,
BedrockAgentThread(None, session_id="test_session_id"),
],
)
@patch.object(boto3, "client", return_value=Mock())
async def test_bedrock_agent_invoke_stream(
client,
thread,
bedrock_agent_unit_test_env,
bedrock_agent_model_with_id,
bedrock_agent_streaming_simple_response,
simple_response,
):
with (
patch.object(BedrockAgent, "_invoke_agent", new_callable=AsyncMock) as mock_invoke_agent,
patch.object(BedrockAgentThread, "create", new_callable=AsyncMock) as mock_start,
patch.object(BedrockAgentThread, "id", "test_session_id"),
):
agent = BedrockAgent(bedrock_agent_model_with_id)
mock_invoke_agent.return_value = bedrock_agent_streaming_simple_response
mock_start.return_value = "test_session_id"
full_message = ""
async for response in agent.invoke_stream(messages="test_input_text", thread=thread):
full_message += response.message.content
assert full_message == simple_response
mock_invoke_agent.assert_called_once_with(
"test_session_id",
"test_input_text",
None,
streamingConfigurations={"streamFinalResponse": True},
sessionState={},
)
# Test case to verify the invocation of BedrockAgent with function call
@patch.object(boto3, "client", return_value=Mock())
async def test_bedrock_agent_invoke_with_function_call(
client,
bedrock_agent_unit_test_env,
bedrock_agent_model_with_id,
bedrock_agent_function_call_response,
bedrock_agent_non_streaming_simple_response,
):
with (
patch.object(BedrockAgent, "_invoke_agent", new_callable=AsyncMock) as mock_invoke_agent,
patch.object(BedrockAgent, "_handle_function_call_contents") as mock_handle_function_call_contents,
patch.object(BedrockAgentThread, "create", new_callable=AsyncMock) as mock_start,
patch.object(BedrockAgentThread, "id", "test_session_id"),
):
agent = BedrockAgent(bedrock_agent_model_with_id)
function_result_contents = [
FunctionResultContent(
id="test_id",
name="test_function",
result="test_result",
metadata={"functionInvocationInput": {"actionGroup": "test_action_group"}},
)
]
mock_handle_function_call_contents.return_value = function_result_contents
agent.function_choice_behavior.maximum_auto_invoke_attempts = 2
mock_invoke_agent.side_effect = [
bedrock_agent_function_call_response,
bedrock_agent_non_streaming_simple_response,
]
mock_start.return_value = "test_session_id"
async for _ in agent.invoke(messages="test_input_text"):
mock_invoke_agent.assert_called_with(
"test_session_id",
"test_input_text",
None,
streamingConfigurations={"streamFinalResponse": False},
sessionState={
"invocationId": "test_invocation_id",
"returnControlInvocationResults": parse_function_result_contents(function_result_contents),
},
)
# Test case to verify the streaming invocation of BedrockAgent with function call
@patch.object(boto3, "client", return_value=Mock())
async def test_bedrock_agent_invoke_stream_with_function_call(
client,
bedrock_agent_unit_test_env,
bedrock_agent_model_with_id,
bedrock_agent_function_call_response,
bedrock_agent_streaming_simple_response,
):
with (
patch.object(BedrockAgent, "_invoke_agent", new_callable=AsyncMock) as mock_invoke_agent,
patch.object(BedrockAgent, "_handle_function_call_contents") as mock_handle_function_call_contents,
patch.object(BedrockAgentThread, "create", new_callable=AsyncMock) as mock_start,
patch.object(BedrockAgentThread, "id", "test_session_id"),
):
agent = BedrockAgent(bedrock_agent_model_with_id)
function_result_contents = [
FunctionResultContent(
id="test_id",
name="test_function",
result="test_result",
metadata={"functionInvocationInput": {"actionGroup": "test_action_group"}},
)
]
mock_handle_function_call_contents.return_value = function_result_contents
agent.function_choice_behavior.maximum_auto_invoke_attempts = 2
mock_invoke_agent.side_effect = [
bedrock_agent_function_call_response,
bedrock_agent_streaming_simple_response,
]
mock_start.return_value = "test_session_id"
async for _ in agent.invoke_stream(messages="test_input_text"):
mock_invoke_agent.assert_called_with(
"test_session_id",
"test_input_text",
None,
streamingConfigurations={"streamFinalResponse": True},
sessionState={
"invocationId": "test_invocation_id",
"returnControlInvocationResults": parse_function_result_contents(function_result_contents),
},
)
# endregion
# region Filename Sanitization Tests
def test_sanitize_filename_simple():
"""Test _sanitize_filename with a simple filename."""
assert BedrockAgent._sanitize_filename("file.txt") == "file.txt"
def test_sanitize_filename_with_spaces():
"""Test _sanitize_filename with spaces in filename."""
assert BedrockAgent._sanitize_filename("my file.txt") == "my file.txt"
def test_sanitize_filename_directory_traversal_unix():
"""Test _sanitize_filename strips Unix-style directory traversal."""
assert BedrockAgent._sanitize_filename("../../../etc/passwd") == "passwd"
assert BedrockAgent._sanitize_filename("../../file.txt") == "file.txt"
assert BedrockAgent._sanitize_filename("/etc/passwd") == "passwd"
def test_sanitize_filename_directory_traversal_windows():
"""Test _sanitize_filename strips Windows-style directory traversal."""
assert BedrockAgent._sanitize_filename("..\\..\\..\\Windows\\System32\\config") == "config"
assert BedrockAgent._sanitize_filename("C:\\Users\\file.txt") == "file.txt"
assert BedrockAgent._sanitize_filename("\\\\server\\share\\file.txt") == "file.txt"
def test_sanitize_filename_mixed_separators():
"""Test _sanitize_filename with mixed path separators."""
assert BedrockAgent._sanitize_filename("../path\\to/file.txt") == "file.txt"
assert BedrockAgent._sanitize_filename("..\\path/to\\file.txt") == "file.txt"
def test_sanitize_filename_null_byte():
"""Test _sanitize_filename removes null bytes."""
assert BedrockAgent._sanitize_filename("file\x00.txt") == "file.txt"
assert BedrockAgent._sanitize_filename("file.txt\x00.exe") == "file.txt.exe"
def test_sanitize_filename_empty():
"""Test _sanitize_filename returns empty string for empty result."""
assert BedrockAgent._sanitize_filename("") == ""
assert BedrockAgent._sanitize_filename("../") == ""
assert BedrockAgent._sanitize_filename("..\\") == ""
def test_sanitize_filename_only_dots():
"""Test _sanitize_filename handles edge cases with dots."""
# Note: os.path.basename("..") returns ".." which is kept as-is
# Only "../" or "..\" patterns get stripped to empty string
assert BedrockAgent._sanitize_filename(".") == "."
def test_sanitize_filename_logs_warning(caplog):
"""Test _sanitize_filename logs warning when filename is sanitized."""
import logging
with caplog.at_level(logging.WARNING):
result = BedrockAgent._sanitize_filename("../malicious/file.txt")
assert result == "file.txt"
assert "potentially malicious path components" in caplog.text
assert "../malicious/file.txt" in caplog.text
assert "file.txt" in caplog.text
def test_sanitize_filename_no_warning_for_clean_filename(caplog):
"""Test _sanitize_filename does not log warning for clean filenames."""
import logging
with caplog.at_level(logging.WARNING):
result = BedrockAgent._sanitize_filename("clean_file.txt")
assert result == "clean_file.txt"
assert "potentially malicious" not in caplog.text
# endregion
@@ -0,0 +1,331 @@
# Copyright (c) Microsoft. All rights reserved.
from collections.abc import AsyncIterable
from unittest.mock import MagicMock, Mock, patch
import boto3
import pytest
from semantic_kernel.agents.agent import Agent, AgentResponseItem, AgentThread
from semantic_kernel.agents.bedrock.models.bedrock_agent_model import BedrockAgentModel
from semantic_kernel.agents.channels.bedrock_agent_channel import BedrockAgentChannel
from semantic_kernel.contents.chat_message_content import ChatMessageContent
from semantic_kernel.contents.streaming_chat_message_content import StreamingChatMessageContent
from semantic_kernel.contents.utils.author_role import AuthorRole
from semantic_kernel.exceptions.agent_exceptions import AgentChatException
@pytest.fixture
@patch.object(boto3, "client", return_value=Mock())
def mock_channel(client):
from semantic_kernel.agents.bedrock.bedrock_agent import BedrockAgentThread
BedrockAgentChannel.model_rebuild()
thread = BedrockAgentThread(client, session_id="test_session_id")
return BedrockAgentChannel(thread=thread)
class ConcreteAgent(Agent):
async def get_response(self, *args, **kwargs) -> ChatMessageContent:
raise NotImplementedError
def invoke(self, *args, **kwargs) -> AsyncIterable[ChatMessageContent]:
raise NotImplementedError
def invoke_stream(self, *args, **kwargs) -> AsyncIterable[StreamingChatMessageContent]:
raise NotImplementedError
@pytest.fixture
def chat_history() -> list[ChatMessageContent]:
return [
ChatMessageContent(role="user", content="Hello, Bedrock!"),
ChatMessageContent(role="assistant", content="Hello, User!"),
ChatMessageContent(role="user", content="How are you?"),
ChatMessageContent(role="assistant", content="I'm good, thank you!"),
]
@pytest.fixture
def chat_history_not_alternate_role() -> list[ChatMessageContent]:
return [
ChatMessageContent(role="user", content="Hello, Bedrock!"),
ChatMessageContent(role="user", content="Hello, User!"),
ChatMessageContent(role="assistant", content="How are you?"),
ChatMessageContent(role="assistant", content="I'm good, thank you!"),
]
@pytest.fixture
def mock_agent():
"""
Fixture that creates a mock BedrockAgent.
"""
from semantic_kernel.agents.bedrock.bedrock_agent import BedrockAgent
# Create mocks
mock_agent = MagicMock(spec=BedrockAgent)
# Set the name and agent_model properties
mock_agent.name = "MockBedrockAgent"
mock_agent.agent_model = MagicMock(spec=BedrockAgentModel)
mock_agent.agent_model.foundation_model = "mock-foundation-model"
return mock_agent
async def test_receive_message(mock_channel, chat_history):
# Test to verify the receive_message functionality
await mock_channel.receive(chat_history)
assert len(mock_channel) == len(chat_history)
async def test_channel_receive_message_with_no_message(mock_channel):
# Test to verify receive_message when no message is received
await mock_channel.receive([])
assert len(mock_channel) == 0
async def test_chat_history_alternation(mock_channel, chat_history_not_alternate_role):
# Test to verify chat history alternates between user and assistant messages
await mock_channel.receive(chat_history_not_alternate_role)
assert all(
mock_channel.messages[i].role != mock_channel.messages[i + 1].role
for i in range(len(chat_history_not_alternate_role) - 1)
)
assert mock_channel.messages[1].content == mock_channel.MESSAGE_PLACEHOLDER
assert mock_channel.messages[4].content == mock_channel.MESSAGE_PLACEHOLDER
async def test_channel_reset(mock_channel, chat_history):
# Test to verify the reset functionality
await mock_channel.receive(chat_history)
assert len(mock_channel) == len(chat_history)
assert len(mock_channel.messages) == len(chat_history)
await mock_channel.reset()
assert len(mock_channel) == 0
assert len(mock_channel.messages) == 0
async def test_receive_appends_history_correctly(mock_channel):
"""Test that the receive method appends messages while ensuring they alternate in author role."""
# Provide a list of messages with identical roles to see if placeholders are inserted
incoming_messages = [
ChatMessageContent(role=AuthorRole.USER, content="User message 1"),
ChatMessageContent(role=AuthorRole.USER, content="User message 2"),
ChatMessageContent(role=AuthorRole.ASSISTANT, content="Assistant message 1"),
ChatMessageContent(role=AuthorRole.ASSISTANT, content="Assistant message 2"),
]
await mock_channel.receive(incoming_messages)
# The final channel.messages should be:
# user message 1, user placeholder, user message 2, assistant placeholder, assistant message 1,
# assistant placeholder, assistant message 2
expected_roles = [
AuthorRole.USER,
AuthorRole.ASSISTANT, # placeholder
AuthorRole.USER,
AuthorRole.ASSISTANT,
AuthorRole.USER, # placeholder
AuthorRole.ASSISTANT,
]
expected_contents = [
"User message 1",
BedrockAgentChannel.MESSAGE_PLACEHOLDER,
"User message 2",
"Assistant message 1",
BedrockAgentChannel.MESSAGE_PLACEHOLDER,
"Assistant message 2",
]
assert len(mock_channel.messages) == len(expected_roles)
for i, (msg, exp_role, exp_content) in enumerate(zip(mock_channel.messages, expected_roles, expected_contents)):
assert msg.role == exp_role, f"Role mismatch at index {i}"
assert msg.content == exp_content, f"Content mismatch at index {i}"
async def test_invoke_raises_exception_for_non_bedrock_agent(mock_channel):
"""Test invoke method raises AgentChatException if the agent provided is not a BedrockAgent."""
# Place a message in the channel so it's not empty
mock_channel.messages.append(ChatMessageContent(role=AuthorRole.USER, content="User message"))
# Create a dummy agent that is not BedrockAgent
non_bedrock_agent = ConcreteAgent()
with pytest.raises(AgentChatException) as exc_info:
_ = [msg async for msg in mock_channel.invoke(non_bedrock_agent)]
assert "Agent is not of the expected type" in str(exc_info.value)
async def test_invoke_raises_exception_if_no_history(mock_channel, mock_agent):
"""Test invoke method raises AgentChatException if no chat history is available."""
with pytest.raises(AgentChatException) as exc_info:
_ = [msg async for msg in mock_channel.invoke(mock_agent)]
assert "No chat history available" in str(exc_info.value)
async def test_invoke_inserts_placeholders_when_history_needs_to_alternate(mock_channel, mock_agent):
"""Test invoke ensures _ensure_history_alternates and _ensure_last_message_is_user are called."""
# Put messages in the channel such that the last message is an assistant's
mock_channel.messages.append(ChatMessageContent(role=AuthorRole.ASSISTANT, content="Assistant 1"))
# Mock agent.invoke to return an async generator
async def mock_invoke(messages: str, thread: AgentThread, sessionState=None, **kwargs):
# We just yield one message as if the agent responded
yield AgentResponseItem(
message=ChatMessageContent(role=AuthorRole.ASSISTANT, content="Mock Agent Response"),
thread=mock_channel.thread,
)
mock_agent.invoke = mock_invoke
# Because the last message is from the assistant, we expect a placeholder user message to be appended
# also the history might need to alternate.
# But since there's only one message, there's nothing to fix except the last message is user.
# We will now add a user message so we do not get the "No chat history available" error
mock_channel.messages.append(ChatMessageContent(role=AuthorRole.USER, content="User 1"))
# Now we do invoke
outputs = [msg async for msg in mock_channel.invoke(mock_agent)]
# We'll check if the response is appended to channel.messages
assert len(outputs) == 1
assert outputs[0][0] is True, "Expected a user-facing response"
agent_response = outputs[0][1]
assert agent_response.content == "Mock Agent Response"
# The channel messages should now have 3 messages: the assistant, the user, and the new agent message
assert len(mock_channel.messages) == 3
assert mock_channel.messages[-1].role == AuthorRole.ASSISTANT
assert mock_channel.messages[-1].content == "Mock Agent Response"
async def test_invoke_stream_raises_error_for_non_bedrock_agent(mock_channel):
"""Test invoke_stream raises AgentChatException if the agent provided is not a BedrockAgent."""
mock_channel.messages.append(ChatMessageContent(role=AuthorRole.USER, content="User message"))
non_bedrock_agent = ConcreteAgent()
with pytest.raises(AgentChatException) as exc_info:
_ = [msg async for msg in mock_channel.invoke_stream(non_bedrock_agent, [])]
assert "Agent is not of the expected type" in str(exc_info.value)
async def test_invoke_stream_raises_no_chat_history(mock_channel, mock_agent):
"""Test invoke_stream raises AgentChatException if no messages in the channel."""
with pytest.raises(AgentChatException) as exc_info:
_ = [msg async for msg in mock_channel.invoke_stream(mock_agent, [])]
assert "No chat history available." in str(exc_info.value)
async def test_invoke_stream_appends_response_message(mock_channel, mock_agent):
"""Test invoke_stream properly yields streaming content and appends an aggregated message at the end."""
# Put a user message in the channel so it won't raise No chat history
mock_channel.messages.append(ChatMessageContent(role=AuthorRole.USER, content="Last user message"))
async def mock_invoke_stream(
messages: str, thread: AgentThread, sessionState=None, **kwargs
) -> AsyncIterable[StreamingChatMessageContent]:
yield AgentResponseItem(
message=StreamingChatMessageContent(
role=AuthorRole.ASSISTANT,
choice_index=0,
content="Hello",
),
thread=mock_channel.thread,
)
yield AgentResponseItem(
message=StreamingChatMessageContent(
role=AuthorRole.ASSISTANT,
choice_index=0,
content=" World",
),
thread=mock_channel.thread,
)
mock_agent.invoke_stream = mock_invoke_stream
# Check that we get the streamed messages and that the summarized message is appended afterward
messages_param = [ChatMessageContent(role=AuthorRole.USER, content="Last user message")] # just to pass the param
streamed_content = [msg async for msg in mock_channel.invoke_stream(mock_agent, messages_param)]
# We expect two streamed chunks: "Hello" and " World"
assert len(streamed_content) == 2
assert streamed_content[0].content == "Hello"
assert streamed_content[1].content == " World"
# Then we expect the channel to append an aggregated ChatMessageContent with "Hello World"
assert len(messages_param) == 2
appended = messages_param[1]
assert appended.role == AuthorRole.ASSISTANT
assert appended.content == "Hello World"
async def test_get_history(mock_channel, chat_history):
"""Test get_history yields messages in reverse order."""
mock_channel.messages = chat_history
reversed_history = [msg async for msg in mock_channel.get_history()]
# Should be reversed
assert reversed_history[0].content == "I'm good, thank you!"
assert reversed_history[1].content == "How are you?"
assert reversed_history[2].content == "Hello, User!"
assert reversed_history[3].content == "Hello, Bedrock!"
async def test_invoke_alternates_history_and_ensures_last_user_message(mock_channel, mock_agent):
"""Test invoke method ensures history alternates and last message is user."""
mock_channel.messages = [
ChatMessageContent(role=AuthorRole.USER, content="User1"),
ChatMessageContent(role=AuthorRole.USER, content="User2"),
ChatMessageContent(role=AuthorRole.ASSISTANT, content="Assist1"),
ChatMessageContent(role=AuthorRole.ASSISTANT, content="Assist2"),
ChatMessageContent(role=AuthorRole.USER, content="User3"),
ChatMessageContent(role=AuthorRole.USER, content="User4"),
ChatMessageContent(role=AuthorRole.ASSISTANT, content="Assist3"),
]
async for _, msg in mock_channel.invoke(mock_agent):
pass
# let's define expected roles from that final structure:
expected_roles = [
AuthorRole.USER,
AuthorRole.ASSISTANT, # placeholder
AuthorRole.USER,
AuthorRole.ASSISTANT,
AuthorRole.USER, # placeholder
AuthorRole.ASSISTANT,
AuthorRole.USER,
AuthorRole.ASSISTANT, # placeholder
AuthorRole.USER,
AuthorRole.ASSISTANT,
AuthorRole.USER, # placeholder
]
expected_contents = [
"User1",
BedrockAgentChannel.MESSAGE_PLACEHOLDER,
"User2",
"Assist1",
BedrockAgentChannel.MESSAGE_PLACEHOLDER,
"Assist2",
"User3",
BedrockAgentChannel.MESSAGE_PLACEHOLDER,
"User4",
"Assist3",
BedrockAgentChannel.MESSAGE_PLACEHOLDER,
]
assert len(mock_channel.messages) == len(expected_roles)
for i, (msg, exp_role, exp_content) in enumerate(zip(mock_channel.messages, expected_roles, expected_contents)):
assert msg.role == exp_role, f"Role mismatch at index {i}. Got {msg.role}, expected {exp_role}"
assert msg.content == exp_content, f"Content mismatch at index {i}. Got {msg.content}, expected {exp_content}"
@@ -0,0 +1,27 @@
# Copyright (c) Microsoft. All rights reserved.
import pytest
from semantic_kernel.agents.bedrock.models.bedrock_agent_event_type import BedrockAgentEventType
def test_bedrock_agent_event_type_values():
"""Test case to verify the values of BedrockAgentEventType enum."""
assert BedrockAgentEventType.CHUNK.value == "chunk"
assert BedrockAgentEventType.TRACE.value == "trace"
assert BedrockAgentEventType.RETURN_CONTROL.value == "returnControl"
assert BedrockAgentEventType.FILES.value == "files"
def test_bedrock_agent_event_type_enum():
"""Test case to verify the type of BedrockAgentEventType enum members."""
assert isinstance(BedrockAgentEventType.CHUNK, BedrockAgentEventType)
assert isinstance(BedrockAgentEventType.TRACE, BedrockAgentEventType)
assert isinstance(BedrockAgentEventType.RETURN_CONTROL, BedrockAgentEventType)
assert isinstance(BedrockAgentEventType.FILES, BedrockAgentEventType)
def test_bedrock_agent_event_type_invalid():
"""Test case to verify error handling for invalid BedrockAgentEventType value."""
with pytest.raises(ValueError):
BedrockAgentEventType("invalid_value")
@@ -0,0 +1,67 @@
# Copyright (c) Microsoft. All rights reserved.
from semantic_kernel.agents.bedrock.models.bedrock_agent_model import BedrockAgentModel
def test_bedrock_agent_model_valid():
"""Test case to verify the BedrockAgentModel with valid data."""
model = BedrockAgentModel(
agentId="test_id",
agentName="test_name",
agentVersion="1.0",
foundationModel="test_model",
agentStatus="CREATING",
)
assert model.agent_id == "test_id"
assert model.agent_name == "test_name"
assert model.agent_version == "1.0"
assert model.foundation_model == "test_model"
assert model.agent_status == "CREATING"
def test_bedrock_agent_model_missing_agent_id():
"""Test case to verify the BedrockAgentModel with missing agentId."""
model = BedrockAgentModel(
agentName="test_name",
agentVersion="1.0",
foundationModel="test_model",
agentStatus="CREATING",
)
assert model.agent_id is None
assert model.agent_name == "test_name"
assert model.agent_version == "1.0"
assert model.foundation_model == "test_model"
assert model.agent_status == "CREATING"
def test_bedrock_agent_model_missing_agent_name():
"""Test case to verify the BedrockAgentModel with missing agentName."""
model = BedrockAgentModel(
agentId="test_id",
agentVersion="1.0",
foundationModel="test_model",
agentStatus="CREATING",
)
assert model.agent_id == "test_id"
assert model.agent_name is None
assert model.agent_version == "1.0"
assert model.foundation_model == "test_model"
assert model.agent_status == "CREATING"
def test_bedrock_agent_model_extra_field():
"""Test case to verify the BedrockAgentModel with an extra field."""
model = BedrockAgentModel(
agentId="test_id",
agentName="test_name",
agentVersion="1.0",
foundationModel="test_model",
agentStatus="CREATING",
extraField="extra_value",
)
assert model.agent_id == "test_id"
assert model.agent_name == "test_name"
assert model.agent_version == "1.0"
assert model.foundation_model == "test_model"
assert model.agent_status == "CREATING"
assert model.extraField == "extra_value"
@@ -0,0 +1,28 @@
# Copyright (c) Microsoft. All rights reserved.
import pytest
from pydantic import ValidationError
from semantic_kernel.agents.bedrock.bedrock_agent_settings import BedrockAgentSettings
def test_bedrock_agent_settings_from_env_vars(bedrock_agent_unit_test_env):
"""Test loading BedrockAgentSettings from environment variables."""
settings = BedrockAgentSettings(env_file_path="fake_path")
assert settings.agent_resource_role_arn == bedrock_agent_unit_test_env["BEDROCK_AGENT_AGENT_RESOURCE_ROLE_ARN"]
assert settings.foundation_model == bedrock_agent_unit_test_env["BEDROCK_AGENT_FOUNDATION_MODEL"]
@pytest.mark.parametrize(
"exclude_list",
[
["BEDROCK_AGENT_AGENT_RESOURCE_ROLE_ARN"],
["BEDROCK_AGENT_FOUNDATION_MODEL"],
],
indirect=True,
)
def test_bedrock_agent_settings_from_env_vars_missing_required(bedrock_agent_unit_test_env):
"""Test loading BedrockAgentSettings from environment variables with missing required fields."""
with pytest.raises(ValidationError):
BedrockAgentSettings(env_file_path="fake_path")
@@ -0,0 +1,23 @@
# Copyright (c) Microsoft. All rights reserved.
import pytest
from semantic_kernel.agents.bedrock.models.bedrock_agent_status import BedrockAgentStatus
def test_bedrock_agent_status_values():
"""Test case to verify the values of BedrockAgentStatus enum."""
assert BedrockAgentStatus.CREATING == "CREATING"
assert BedrockAgentStatus.PREPARING == "PREPARING"
assert BedrockAgentStatus.PREPARED == "PREPARED"
assert BedrockAgentStatus.NOT_PREPARED == "NOT_PREPARED"
assert BedrockAgentStatus.DELETING == "DELETING"
assert BedrockAgentStatus.FAILED == "FAILED"
assert BedrockAgentStatus.VERSIONING == "VERSIONING"
assert BedrockAgentStatus.UPDATING == "UPDATING"
def test_bedrock_agent_status_invalid_value():
"""Test case to verify error handling for invalid BedrockAgentStatus value."""
with pytest.raises(ValueError):
BedrockAgentStatus("INVALID_STATUS")