Skip to content

Commit

Permalink
Fix functions_view.py (#1213)
Browse files Browse the repository at this point in the history
### Motivation and Context
#1212 

### Description
Fixed a bug in the process of checking native function.


---------

Co-authored-by: Abby Harrison <54643756+awharrison-28@users.noreply.github.com>
Co-authored-by: Devis Lucato <dluc@users.noreply.github.com>
  • Loading branch information
3 people authored Jun 9, 2023
1 parent b2e1548 commit f60d7ba
Show file tree
Hide file tree
Showing 2 changed files with 166 additions and 1 deletion.
15 changes: 14 additions & 1 deletion python/semantic_kernel/skill_definition/functions_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,17 @@ def is_semantic(self, skill_name: str, function_name: str) -> bool:
return as_sf

def is_native(self, skill_name: str, function_name: str) -> bool:
return not self.is_semantic(skill_name, function_name)
as_sf = self._semantic_functions.get(skill_name, [])
as_sf = any(f.name == function_name for f in as_sf)

as_nf = self._native_functions.get(skill_name, [])
as_nf = any(f.name == function_name for f in as_nf)

if as_sf and as_nf:
raise KernelException(
KernelException.ErrorCodes.AmbiguousImplementation,
f"There are 2 functions with the same name: {function_name}."
f"One is native and the other semantic.",
)

return as_nf
152 changes: 152 additions & 0 deletions python/tests/unit/skill_definition/test_functions_view.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
# Copyright (c) Microsoft. All rights reserved.

import pytest
from semantic_kernel.kernel_exception import KernelException
from semantic_kernel.skill_definition.function_view import FunctionView
from semantic_kernel.skill_definition.functions_view import FunctionsView, FunctionView


def test_add_semantic_function():
view = FunctionView(
name="function1",
skill_name="skill1",
description="Semantic function",
parameters=[],
is_semantic=True,
is_asynchronous=True,
)
functions_view = FunctionsView()
functions_view.add_function(view)
semantic_functions = functions_view._semantic_functions.get("skill1")
assert len(semantic_functions) == 1
assert semantic_functions[0] == view


def test_add_native_function():
view = FunctionView(
name="function2",
skill_name="skill2",
description="Native function",
parameters=[],
is_semantic=False,
is_asynchronous=True,
)
functions_view = FunctionsView()
functions_view.add_function(view)
native_functions = functions_view._native_functions.get("skill2")
assert len(native_functions) == 1
assert native_functions[0] == view


def test_add_multiple_functions():
semantic_function = FunctionView(
name="function1",
skill_name="skill1",
description="Semantic function",
parameters=[],
is_semantic=True,
is_asynchronous=True,
)
native_function = FunctionView(
name="function2",
skill_name="skill2",
description="Native function",
parameters=[],
is_semantic=False,
is_asynchronous=True,
)
functions_view = FunctionsView()
functions_view.add_function(semantic_function)
functions_view.add_function(native_function)
semantic_functions = functions_view._semantic_functions.get("skill1")
native_functions = functions_view._native_functions.get("skill2")
assert len(semantic_functions) == 1
assert semantic_functions[0] == semantic_function
assert len(native_functions) == 1
assert native_functions[0] == native_function


def test_is_semantic():
semantic_function = FunctionView(
name="function1",
skill_name="skill1",
description="Semantic function",
parameters=[],
is_semantic=True,
is_asynchronous=True,
)
native_function = FunctionView(
name="function2",
skill_name="skill2",
description="Native function",
parameters=[],
is_semantic=False,
is_asynchronous=True,
)
functions_view = FunctionsView()
functions_view.add_function(semantic_function)
functions_view.add_function(native_function)
assert functions_view.is_semantic("skill1", "function1") is True
assert functions_view.is_semantic("skill2", "function2") is False
assert functions_view.is_semantic("skill1", "unregistered_function") is False


def test_is_native():
semantic_function = FunctionView(
name="function1",
skill_name="skill1",
description="Semantic function",
parameters=[],
is_semantic=True,
is_asynchronous=True,
)
native_function = FunctionView(
name="function2",
skill_name="skill2",
description="Native function",
parameters=[],
is_semantic=False,
is_asynchronous=True,
)
functions_view = FunctionsView()
functions_view.add_function(semantic_function)
functions_view.add_function(native_function)
assert functions_view.is_native("skill1", "function1") is False
assert functions_view.is_native("skill2", "function2") is True
assert functions_view.is_native("skill2", "unregistered_function") is False


def test_ambiguous_implementation():
semantic_function = FunctionView(
name="function1",
skill_name="skill1",
description="Semantic function",
parameters=[],
is_semantic=True,
is_asynchronous=True,
)
native_function = FunctionView(
name="function1",
skill_name="skill1",
description="Native function",
parameters=[],
is_semantic=False,
is_asynchronous=True,
)
functions_view = FunctionsView()
functions_view.add_function(semantic_function)
functions_view.add_function(native_function)

with pytest.raises(KernelException) as exc_info:
functions_view.is_semantic("skill1", "function1")

assert (
exc_info.value.error_code == KernelException.ErrorCodes.AmbiguousImplementation
)

with pytest.raises(KernelException) as exc_info:
functions_view.is_native("skill1", "function1")

assert (
exc_info.value.error_code == KernelException.ErrorCodes.AmbiguousImplementation
)

0 comments on commit f60d7ba

Please sign in to comment.