Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ def kernel_function_metadata_to_bedrock_function_schema(function_metadata: Kerne
"parameters": {
parameter.name: kernel_function_parameter_to_bedrock_function_parameter(parameter)
for parameter in function_metadata.parameters
if parameter.include_in_function_choices
},
# This field controls whether user confirmation is required to invoke the function.
# If this is set to "ENABLED", the user will be prompted to confirm the function invocation.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ def kernel_function_metadata_to_function_call_format(metadata: KernelFunctionMet
"description": metadata.description or "",
"input_schema": {
"type": "object",
"properties": {p.name: p.schema_data for p in metadata.parameters},
"required": [p.name for p in metadata.parameters if p.is_required],
"properties": {p.name: p.schema_data for p in metadata.parameters if p.include_in_function_choices},
"required": [p.name for p in metadata.parameters if p.is_required and p.include_in_function_choices],
},
}
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,14 @@ def update_settings_from_function_choice_configuration(
"inputSchema": {
"json": {
"type": "object",
"properties": {param.name: param.schema_data for param in function.parameters},
"required": [p.name for p in function.parameters if p.is_required],
"properties": {
param.name: param.schema_data
for param in function.parameters
if param.include_in_function_choices
},
"required": [
p.name for p in function.parameters if p.is_required and p.include_in_function_choices
],
}
},
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,17 +149,18 @@ def format_tool_message(message: ChatMessageContent) -> list[Part]:
def kernel_function_metadata_to_google_ai_function_call_format(metadata: KernelFunctionMetadata) -> dict[str, Any]:
"""Convert the kernel function metadata to function calling format."""
parameters: dict[str, Any] | None = None
if metadata.parameters:
visible_parameters = [p for p in metadata.parameters if p.include_in_function_choices]
if visible_parameters:
properties = {}
for param in metadata.parameters:
for param in visible_parameters:
if param.name is None:
continue
prop_schema = sanitize_schema_for_google_ai(param.schema_data) if param.schema_data else param.schema_data
properties[param.name] = prop_schema
parameters = {
"type": "object",
"properties": properties,
"required": [p.name for p in metadata.parameters if p.is_required and p.name is not None],
"required": [p.name for p in visible_parameters if p.is_required and p.name is not None],
}
return {
"name": metadata.custom_fully_qualified_name(GEMINI_FUNCTION_NAME_SEPARATOR),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,9 @@ def format_tool_message(message: ChatMessageContent) -> list[Part]:
def kernel_function_metadata_to_vertex_ai_function_call_format(metadata: KernelFunctionMetadata) -> FunctionDeclaration:
"""Convert the kernel function metadata to function calling format."""
properties: dict[str, Any] = {}
if metadata.parameters:
for param in metadata.parameters:
visible_parameters = [p for p in metadata.parameters if p.include_in_function_choices]
if visible_parameters:
for param in visible_parameters:
if param.name is None:
continue
prop_schema = sanitize_schema_for_google_ai(param.schema_data) if param.schema_data else param.schema_data
Expand All @@ -151,7 +152,7 @@ def kernel_function_metadata_to_vertex_ai_function_call_format(metadata: KernelF
parameters={
"type": "object",
"properties": properties,
"required": [p.name for p in metadata.parameters if p.is_required and p.name is not None],
"required": [p.name for p in visible_parameters if p.is_required and p.name is not None],
},
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@

from semantic_kernel.agents.bedrock.action_group_utils import (
BEDROCK_FUNCTION_ALLOWED_PARAMETER_TYPES,
kernel_function_metadata_to_bedrock_function_schema,
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.functions.kernel_function_metadata import KernelFunctionMetadata
from semantic_kernel.functions.kernel_parameter_metadata import KernelParameterMetadata
from semantic_kernel.kernel import Kernel


Expand All @@ -35,6 +38,27 @@ def test_kernel_function_to_bedrock_function_schema(kernel_with_function: Kernel
}


def test_kernel_function_metadata_to_bedrock_function_schema_skips_params_excluded_from_function_choices():
metadata = KernelFunctionMetadata(
name="lookup",
description="Look up a user",
is_prompt=False,
parameters=[
KernelParameterMetadata(name="query", schema_data={"type": "string"}, is_required=True),
KernelParameterMetadata(
name="token",
schema_data={"type": "string"},
is_required=True,
include_in_function_choices=False,
),
],
)

result = kernel_function_metadata_to_bedrock_function_schema(metadata)

assert list(result["parameters"]) == ["query"]


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"}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Copyright (c) Microsoft. All rights reserved.

from semantic_kernel.connectors.ai.anthropic.services.utils import kernel_function_metadata_to_function_call_format
from semantic_kernel.functions.kernel_function_metadata import KernelFunctionMetadata
from semantic_kernel.functions.kernel_parameter_metadata import KernelParameterMetadata


def test_function_call_format_skips_params_excluded_from_function_choices() -> None:
metadata = KernelFunctionMetadata(
name="lookup",
description="Look up a user",
is_prompt=False,
parameters=[
KernelParameterMetadata(
name="query", description="What to look up", schema_data={"type": "string"}, is_required=True
),
KernelParameterMetadata(
name="token",
description="Internal",
schema_data={"type": "string"},
is_required=True,
include_in_function_choices=False,
),
],
)

result = kernel_function_metadata_to_function_call_format(metadata)

assert list(result["input_schema"]["properties"]) == ["query"]
assert result["input_schema"]["required"] == ["query"]
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
from semantic_kernel.contents.utils.author_role import AuthorRole
from semantic_kernel.contents.utils.finish_reason import FinishReason
from semantic_kernel.exceptions.service_exceptions import ServiceInvalidRequestError
from semantic_kernel.functions.kernel_function_metadata import KernelFunctionMetadata
from semantic_kernel.functions.kernel_parameter_metadata import KernelParameterMetadata
from semantic_kernel.kernel import Kernel


Expand Down Expand Up @@ -441,3 +443,32 @@ def test_update_settings_from_function_choice_configuration_required_one(mock_be
assert mock_bedrock_settings.tool_choice == {"tool": {"name": "plugin-function"}}
assert len(mock_bedrock_settings.tools) == 1
assert mock_bedrock_settings.tools[0]["toolSpec"]["name"] == "plugin-function"


def test_update_settings_from_function_choice_configuration_skips_params_excluded_from_function_choices() -> None:
metadata = KernelFunctionMetadata(
name="lookup",
description="Look up a user",
is_prompt=False,
parameters=[
KernelParameterMetadata(
name="query", description="What to look up", schema_data={"type": "string"}, is_required=True
),
KernelParameterMetadata(
name="token",
description="Internal",
schema_data={"type": "string"},
is_required=True,
include_in_function_choices=False,
),
],
)
config = FunctionCallChoiceConfiguration()
config.available_functions = [metadata]
settings = BedrockChatPromptExecutionSettings()

update_settings_from_function_choice_configuration(config, settings, FunctionChoiceType.AUTO)

schema = settings.tools[0]["toolSpec"]["inputSchema"]["json"]
assert list(schema["properties"]) == ["query"]
assert schema["required"] == ["query"]
Original file line number Diff line number Diff line change
Expand Up @@ -199,3 +199,39 @@ def test_google_ai_function_call_format_empty_parameters() -> None:
)
result = kernel_function_metadata_to_google_ai_function_call_format(metadata)
assert result["parameters"] is None


def test_google_ai_function_call_format_skips_params_excluded_from_function_choices() -> None:
metadata = KernelFunctionMetadata(
name="lookup",
description="Look up a user",
is_prompt=False,
parameters=[
KernelParameterMetadata(
name="query", description="What to look up", schema_data={"type": "string"}, is_required=True
),
KernelParameterMetadata(
name="token",
description="Internal",
schema_data={"type": "string"},
is_required=True,
include_in_function_choices=False,
),
],
)
result = kernel_function_metadata_to_google_ai_function_call_format(metadata)
assert list(result["parameters"]["properties"]) == ["query"]
assert result["parameters"]["required"] == ["query"]


def test_google_ai_function_call_format_all_params_excluded_gives_no_parameters() -> None:
metadata = KernelFunctionMetadata(
name="hidden_only",
description="Only hidden parameters",
is_prompt=False,
parameters=[
KernelParameterMetadata(name="token", schema_data={"type": "string"}, include_in_function_choices=False),
],
)
result = kernel_function_metadata_to_google_ai_function_call_format(metadata)
assert result["parameters"] is None
Original file line number Diff line number Diff line change
Expand Up @@ -197,3 +197,27 @@ def test_vertex_ai_function_call_format_empty_parameters() -> None:
)
result = kernel_function_metadata_to_vertex_ai_function_call_format(metadata)
assert isinstance(result, FunctionDeclaration)


def test_vertex_ai_function_call_format_skips_params_excluded_from_function_choices() -> None:
metadata = KernelFunctionMetadata(
name="lookup",
description="Look up a user",
is_prompt=False,
parameters=[
KernelParameterMetadata(
name="query", description="What to look up", schema_data={"type": "string"}, is_required=True
),
KernelParameterMetadata(
name="token",
description="Internal",
schema_data={"type": "string"},
is_required=True,
include_in_function_choices=False,
),
],
)
result = kernel_function_metadata_to_vertex_ai_function_call_format(metadata)
schema = type(result).to_dict(result)["parameters"]
assert list(schema["properties"]) == ["query"]
assert schema["required"] == ["query"]
Loading