mirror of
https://github.com/microsoft/semantic-kernel.git
synced 2026-10-12 02:19:06 +00:00
Python: Adgudime/python/serialization/skill definition (#2329)
This is part 4 of the Serialization work for semantic kernel. Corresponding issue: https://github.com/microsoft/semantic-kernel/issues/131 ### Motivation and Context While there are no user facing changes, the ReadOnlySkillCollection has been modified to remove circular dependencies that were causing issues with serialization. <!-- Thank you for your contribution to the semantic-kernel repo! Please help reviewers and future users, providing the following information: 1. Why is this change required? 2. What problem does it solve? 3. What scenario does it contribute to? 4. If it fixes an open issue, please link to the issue here. --> ### Description <!-- Describe your changes, the overall approach, the underlying design. These notes will help understanding how your code works. Thanks! --> ### Contribution Checklist <!-- Before submitting this PR, please make sure: --> - [x] The code builds clean without any errors or warnings - [x] The PR follows the [SK Contribution Guidelines](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md) and the [pre-submission formatting script](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md#development-scripts) raises no violations - [x] All unit tests pass, and I have added new tests where possible - [x] I didn't break anyone 😄 --------- Co-authored-by: Abby Harrison <[email protected]> Co-authored-by: Abby Harrison <[email protected]>
This commit is contained in:
co-authored by
Abby Harrison
Abby Harrison
parent
e8342c60a1
commit
77eeff2cd6
@@ -18,7 +18,7 @@ def test_add_semantic_function():
|
||||
)
|
||||
functions_view = FunctionsView()
|
||||
functions_view.add_function(view)
|
||||
semantic_functions = functions_view._semantic_functions.get("skill1")
|
||||
semantic_functions = functions_view.semantic_functions.get("skill1")
|
||||
assert len(semantic_functions) == 1
|
||||
assert semantic_functions[0] == view
|
||||
|
||||
@@ -34,7 +34,7 @@ def test_add_native_function():
|
||||
)
|
||||
functions_view = FunctionsView()
|
||||
functions_view.add_function(view)
|
||||
native_functions = functions_view._native_functions.get("skill2")
|
||||
native_functions = functions_view.native_functions.get("skill2")
|
||||
assert len(native_functions) == 1
|
||||
assert native_functions[0] == view
|
||||
|
||||
@@ -59,8 +59,8 @@ def test_add_multiple_functions():
|
||||
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")
|
||||
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
|
||||
|
||||
@@ -5,6 +5,7 @@ import pydantic as pdt
|
||||
import pytest
|
||||
import typing_extensions as te
|
||||
|
||||
from semantic_kernel import SKFunctionBase
|
||||
from semantic_kernel.core_skills.conversation_summary_skill import (
|
||||
ConversationSummarySkill,
|
||||
)
|
||||
@@ -17,6 +18,17 @@ from semantic_kernel.core_skills.time_skill import TimeSkill
|
||||
from semantic_kernel.core_skills.wait_skill import WaitSkill
|
||||
from semantic_kernel.core_skills.web_search_engine_skill import WebSearchEngineSkill
|
||||
from semantic_kernel.sk_pydantic import PydanticField, SKBaseModel
|
||||
from semantic_kernel.skill_definition.function_view import FunctionView
|
||||
from semantic_kernel.skill_definition.functions_view import FunctionsView
|
||||
from semantic_kernel.skill_definition.parameter_view import ParameterView
|
||||
from semantic_kernel.skill_definition.read_only_skill_collection import (
|
||||
ReadOnlySkillCollection,
|
||||
)
|
||||
from semantic_kernel.skill_definition.read_only_skill_collection_base import (
|
||||
ReadOnlySkillCollectionBase,
|
||||
)
|
||||
from semantic_kernel.skill_definition.skill_collection import SkillCollection
|
||||
from semantic_kernel.skill_definition.skill_collection_base import SkillCollectionBase
|
||||
from semantic_kernel.template_engine.blocks.block import Block
|
||||
from semantic_kernel.template_engine.blocks.block_types import BlockTypes
|
||||
from semantic_kernel.template_engine.blocks.code_block import CodeBlock
|
||||
@@ -52,6 +64,37 @@ class _Serializable(t.Protocol):
|
||||
@pytest.fixture()
|
||||
def sk_factory() -> t.Callable[[t.Type[_Serializable]], _Serializable]:
|
||||
"""Return a factory for various objects in semantic-kernel."""
|
||||
|
||||
def create_functions_view() -> FunctionsView:
|
||||
"""Return a functions view."""
|
||||
result = FunctionsView()
|
||||
result.add_function(
|
||||
FunctionView(
|
||||
name="function1",
|
||||
skill_name="skill1",
|
||||
description="Native function",
|
||||
parameters=[],
|
||||
is_semantic=False,
|
||||
is_asynchronous=True,
|
||||
)
|
||||
)
|
||||
result.add_function(
|
||||
FunctionView(
|
||||
name="function1",
|
||||
skill_name="skill1",
|
||||
description="Semantic function",
|
||||
parameters=[],
|
||||
is_semantic=True,
|
||||
is_asynchronous=True,
|
||||
)
|
||||
)
|
||||
return result
|
||||
|
||||
def create_skill_collection() -> SkillCollection:
|
||||
"""Return a skill collection."""
|
||||
# TODO: Add a few skills to this collection.
|
||||
return SkillCollection()
|
||||
|
||||
cls_obj_map = {
|
||||
Block: Block("foo"),
|
||||
CodeBlock: CodeBlock("foo"),
|
||||
@@ -62,6 +105,17 @@ def sk_factory() -> t.Callable[[t.Type[_Serializable]], _Serializable]:
|
||||
CodeTokenizer: CodeTokenizer(log=logging.getLogger("test")),
|
||||
PromptTemplateEngine: PromptTemplateEngine(logger=logging.getLogger("test")),
|
||||
TemplateTokenizer: TemplateTokenizer(log=logging.getLogger("test")),
|
||||
ParameterView: ParameterView("foo", "bar", default_value="baz"),
|
||||
FunctionView: FunctionView(
|
||||
"foo",
|
||||
"bar",
|
||||
"baz",
|
||||
[ParameterView("qux", "bar", "baz")],
|
||||
True,
|
||||
False,
|
||||
),
|
||||
FunctionsView: create_functions_view(),
|
||||
SkillCollection: create_skill_collection(),
|
||||
}
|
||||
|
||||
def constructor(cls: t.Type[_Serializable]) -> _Serializable:
|
||||
@@ -88,6 +142,17 @@ PROTOCOLS = [
|
||||
TextRenderer,
|
||||
]
|
||||
|
||||
BASE_CLASSES = [
|
||||
ReadOnlySkillCollectionBase,
|
||||
SkillCollectionBase,
|
||||
SKFunctionBase,
|
||||
]
|
||||
|
||||
# Classes that don't need serialization
|
||||
UNSERIALIZED_CLASSES = [
|
||||
ReadOnlySkillCollection,
|
||||
]
|
||||
|
||||
STATELESS_CLASSES = [
|
||||
CodeTokenizer,
|
||||
PromptTemplateEngine,
|
||||
@@ -103,12 +168,22 @@ PYDANTIC_MODELS = [
|
||||
TextBlock,
|
||||
ValBlock,
|
||||
VarBlock,
|
||||
ParameterView,
|
||||
FunctionView,
|
||||
FunctionsView,
|
||||
SkillCollection,
|
||||
]
|
||||
|
||||
|
||||
class TestUsageInPydanticFields:
|
||||
@pytest.mark.parametrize(
|
||||
"sk_type", PROTOCOLS + ENUMS + PYDANTIC_MODELS + STATELESS_CLASSES
|
||||
"sk_type",
|
||||
BASE_CLASSES
|
||||
+ PROTOCOLS
|
||||
+ ENUMS
|
||||
+ PYDANTIC_MODELS
|
||||
+ STATELESS_CLASSES
|
||||
+ UNSERIALIZED_CLASSES,
|
||||
)
|
||||
def test_usage_as_optional_field(
|
||||
self,
|
||||
|
||||
Reference in New Issue
Block a user