Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Python: Add json schema handling. Add experimental tag to OpenAPI and Memory Connectors. #6335

Merged
merged 9 commits into from
May 20, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
temperature=0.7,
top_p=0.8,
function_call_behavior=FunctionCallBehavior.EnableFunctions(
auto_invoke=True, filters={"included_plugins": ["math"]}
auto_invoke=True, filters={"included_plugins": ["math", "time"]}
),
)

Expand Down
44 changes: 17 additions & 27 deletions python/semantic_kernel/connectors/ai/open_ai/services/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,6 @@
logger = logging.getLogger(__name__)


TYPE_MAPPER = {
"str": "string",
"int": "number",
"float": "number",
"bool": "boolean",
"list": "array",
"dict": "object",
}


def update_settings_from_function_call_configuration(
function_call_configuration: "FunctionCallConfiguration", settings: "OpenAIChatPromptExecutionSettings"
) -> None:
Expand All @@ -44,31 +34,31 @@ def update_settings_from_function_call_configuration(

def kernel_function_metadata_to_openai_tool_format(metadata: KernelFunctionMetadata) -> dict[str, Any]:
"""Convert the kernel function metadata to OpenAI format."""

def parse_schema(schema_data):
"""Recursively parse the schema data to include nested properties."""
if schema_data.get("type") == "object":
return {
"type": "object",
"properties": {key: parse_schema(value) for key, value in schema_data.get("properties", {}).items()},
"description": schema_data.get("description", ""),
}
else:
return {
"type": schema_data.get("type", "string"),
"description": schema_data.get("description", ""),
**({"enum": schema_data.get("enum")} if "enum" in schema_data else {}),
}

return {
"type": "function",
"function": {
"name": metadata.fully_qualified_name,
"description": metadata.description or "",
"parameters": {
"type": "object",
"properties": {
param.name: {
"description": param.description or "",
"type": parse_parameter_type(param.type_),
**({"enum": param.enum} if hasattr(param, "enum") else {}), # Added support for enum
}
for param in metadata.parameters
},
"properties": {param.name: parse_schema(param.schema_data) for param in metadata.parameters},
"required": [p.name for p in metadata.parameters if p.is_required],
},
},
}


def parse_parameter_type(param_type: str | None) -> str:
"""Parse the parameter type."""
if not param_type:
return "string"
if "," in param_type:
param_type = param_type.split(",", maxsplit=1)[0]
return TYPE_MAPPER.get(param_type, "string")
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from semantic_kernel.connectors.memory.astradb.utils import AsyncSession
from semantic_kernel.connectors.telemetry import APP_INFO
from semantic_kernel.exceptions import ServiceResponseException
from semantic_kernel.utils.experimental_decorator import experimental_class

ASTRA_CALLER_IDENTITY: str
SEMANTIC_KERNEL_VERSION = APP_INFO.get("Semantic-Kernel-Version")
Expand All @@ -15,6 +16,7 @@
ASTRA_CALLER_IDENTITY = "semantic-kernel"


@experimental_class
class AstraClient:
def __init__(
self,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from semantic_kernel.exceptions import MemoryConnectorInitializationError
from semantic_kernel.memory.memory_record import MemoryRecord
from semantic_kernel.memory.memory_store_base import MemoryStoreBase
from semantic_kernel.utils.experimental_decorator import experimental_class

MAX_DIMENSIONALITY = 20000
MAX_UPSERT_BATCH_SIZE = 100
Expand All @@ -28,6 +29,7 @@
logger: logging.Logger = logging.getLogger(__name__)


@experimental_class
class AstraDBMemoryStore(MemoryStoreBase):
"""A memory store that uses Astra database as the backend."""

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
from pydantic import SecretStr

from semantic_kernel.connectors.memory.memory_settings_base import BaseModelSettings
from semantic_kernel.utils.experimental_decorator import experimental_class


@experimental_class
class AstraDBSettings(BaseModelSettings):
"""AstraDB model settings

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

from semantic_kernel.connectors.memory.memory_settings_base import BaseModelSettings
from semantic_kernel.kernel_pydantic import HttpsUrl
from semantic_kernel.utils.experimental_decorator import experimental_class


@experimental_class
class AzureAISearchSettings(BaseModelSettings):
"""Azure AI Search model settings currently used by the AzureCognitiveSearchMemoryStore connector

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,12 @@
from semantic_kernel.exceptions import MemoryConnectorInitializationError, MemoryConnectorResourceNotFound
from semantic_kernel.memory.memory_record import MemoryRecord
from semantic_kernel.memory.memory_store_base import MemoryStoreBase
from semantic_kernel.utils.experimental_decorator import experimental_class

logger: logging.Logger = logging.getLogger(__name__)


@experimental_class
class AzureCognitiveSearchMemoryStore(MemoryStoreBase):
_search_index_client: SearchIndexClient = None
_vector_size: int = None
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@
from semantic_kernel.exceptions import MemoryConnectorInitializationError
from semantic_kernel.memory.memory_record import MemoryRecord
from semantic_kernel.memory.memory_store_base import MemoryStoreBase
from semantic_kernel.utils.experimental_decorator import experimental_class

logger: logging.Logger = logging.getLogger(__name__)


@experimental_class
class AzureCosmosDBMemoryStore(MemoryStoreBase):
"""A memory store that uses AzureCosmosDB for MongoDB vCore, to perform vector similarity search on a fully
managed MongoDB compatible database service.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
from numpy import ndarray

from semantic_kernel.memory.memory_record import MemoryRecord
from semantic_kernel.utils.experimental_decorator import experimental_class


# Abstract class similar to the original data store that allows API level abstraction
@experimental_class
class AzureCosmosDBStoreApi(ABC):
@abstractmethod
async def create_collection(self, collection_name: str) -> None:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
from pydantic import SecretStr

from semantic_kernel.connectors.memory.memory_settings_base import BaseModelSettings
from semantic_kernel.utils.experimental_decorator import experimental_class


@experimental_class
class AzureCosmosDBSettings(BaseModelSettings):
"""Azure CosmosDB model settings

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@

from semantic_kernel.connectors.telemetry import HTTP_USER_AGENT
from semantic_kernel.exceptions import ServiceInitializationError
from semantic_kernel.utils.experimental_decorator import experimental_function


@experimental_function
class CosmosDBSimilarityType(str, Enum):
"""Cosmos DB Similarity Type as enumerator."""

Expand All @@ -20,6 +22,7 @@ class CosmosDBSimilarityType(str, Enum):
"""Euclidean distance"""


@experimental_function
class CosmosDBVectorSearchType(str, Enum):
"""Cosmos DB Vector Search Type as enumerator."""

Expand All @@ -29,6 +32,7 @@ class CosmosDBVectorSearchType(str, Enum):
"""HNSW vector index"""


@experimental_function
def get_mongodb_search_client(connection_string: str, application_name: str):
"""
Returns a client for Azure Cosmos Mongo vCore Vector DB
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@
CosmosDBVectorSearchType,
)
from semantic_kernel.memory.memory_record import MemoryRecord
from semantic_kernel.utils.experimental_decorator import experimental_class


@experimental_class
class MongoStoreApi(AzureCosmosDBStoreApi):
database = None
collection_name: str
Expand Down
Original file line number Diff line number Diff line change
@@ -1,36 +1,38 @@
# Copyright (c) Microsoft. All rights reserved.

import json
from typing import Any, Dict, List, Tuple
from typing import Any, List, Tuple

import numpy as np
from azure.cosmos.aio import ContainerProxy, CosmosClient, DatabaseProxy
from numpy import ndarray

from semantic_kernel.memory.memory_record import MemoryRecord
from semantic_kernel.memory.memory_store_base import MemoryStoreBase
from semantic_kernel.utils.experimental_decorator import experimental_class


# You can read more about vector search using AzureCosmosDBNoSQL here.
# https://aka.ms/CosmosVectorSearch
@experimental_class
class AzureCosmosDBNoSQLMemoryStore(MemoryStoreBase):
cosmos_client: CosmosClient = None
database: DatabaseProxy
container: ContainerProxy
database_name: str = None
partition_key: str = None
vector_embedding_policy: [Dict[str, Any]] = None
indexing_policy: [Dict[str, Any]] = None
cosmos_container_properties: [Dict[str, Any]] = None
vector_embedding_policy: dict[str, Any] | None = None
indexing_policy: dict[str, Any] | None = None
cosmos_container_properties: dict[str, Any] | None = None

def __init__(
self,
cosmos_client: CosmosClient,
database_name: str,
partition_key: str,
vector_embedding_policy: [Dict[str, Any]],
indexing_policy: [Dict[str, Any]],
cosmos_container_properties: [Dict[str, Any]],
vector_embedding_policy: dict[str, Any] | None = None,
indexing_policy: dict[str, Any] | None = None,
cosmos_container_properties: dict[str, Any] | None = None,
):
if indexing_policy["vectorIndexes"] is None or len(indexing_policy["vectorIndexes"]) == 0:
raise ValueError("vectorIndexes cannot be null or empty in the indexing_policy.")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from semantic_kernel.exceptions import ServiceInitializationError, ServiceResourceNotFoundError
from semantic_kernel.memory.memory_record import MemoryRecord
from semantic_kernel.memory.memory_store_base import MemoryStoreBase
from semantic_kernel.utils.experimental_decorator import experimental_class

if TYPE_CHECKING:
import chromadb
Expand All @@ -18,6 +19,7 @@
logger: logging.Logger = logging.getLogger(__name__)


@experimental_class
class ChromaMemoryStore(MemoryStoreBase):
_client: "chromadb.Client"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

from pydantic_settings import BaseSettings

from semantic_kernel.utils.experimental_decorator import experimental_class


@experimental_class
class BaseModelSettings(BaseSettings):
env_file_path: str | None = None

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from semantic_kernel.exceptions import ServiceResourceNotFoundError, ServiceResponseException
from semantic_kernel.memory.memory_record import MemoryRecord
from semantic_kernel.memory.memory_store_base import MemoryStoreBase
from semantic_kernel.utils.experimental_decorator import experimental_class, experimental_function

logger: logging.Logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -47,6 +48,7 @@
]


@experimental_function
def memoryrecord_to_milvus_dict(mem: MemoryRecord) -> Dict[str, Any]:
"""Convert a memoryrecord into a dict.
Args:
Expand All @@ -66,6 +68,7 @@ def memoryrecord_to_milvus_dict(mem: MemoryRecord) -> Dict[str, Any]:
return ret_dict


@experimental_function
def milvus_dict_to_memoryrecord(milvus_dict: Dict[str, Any]) -> MemoryRecord:
"""Convert Milvus search result dict into MemoryRecord.

Expand All @@ -92,6 +95,7 @@ def milvus_dict_to_memoryrecord(milvus_dict: Dict[str, Any]) -> MemoryRecord:
)


@experimental_function
def create_fields(dimensions: int) -> List[FieldSchema]:
return [
FieldSchema(
Expand Down Expand Up @@ -138,6 +142,7 @@ def create_fields(dimensions: int) -> List[FieldSchema]:
]


@experimental_class
class MilvusMemoryStore(MemoryStoreBase):
def __init__(
self,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,12 @@
from semantic_kernel.exceptions import ServiceResourceNotFoundError
from semantic_kernel.memory.memory_record import MemoryRecord
from semantic_kernel.memory.memory_store_base import MemoryStoreBase
from semantic_kernel.utils.experimental_decorator import experimental_class

logger: logging.Logger = logging.getLogger(__name__)


@experimental_class
class MongoDBAtlasMemoryStore(MemoryStoreBase):
"""Memory Store for MongoDB Atlas Vector Search Connections"""

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
from pydantic import SecretStr

from semantic_kernel.connectors.memory.memory_settings_base import BaseModelSettings
from semantic_kernel.utils.experimental_decorator import experimental_class


@experimental_class
class MongoDBAtlasSettings(BaseModelSettings):
"""MongoDB Atlas model settings

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
)
from semantic_kernel.memory.memory_record import MemoryRecord
from semantic_kernel.memory.memory_store_base import MemoryStoreBase
from semantic_kernel.utils.experimental_decorator import experimental_class

# Limitations set by Pinecone at https://docs.pinecone.io/reference/known-limitations
MAX_DIMENSIONALITY = 20000
Expand All @@ -32,6 +33,7 @@
logger: logging.Logger = logging.getLogger(__name__)


@experimental_class
class PineconeMemoryStore(MemoryStoreBase):
"""A memory store that uses Pinecone as the backend."""

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
from pydantic import SecretStr

from semantic_kernel.connectors.memory.memory_settings_base import BaseModelSettings
from semantic_kernel.utils.experimental_decorator import experimental_class


@experimental_class
class PineconeSettings(BaseModelSettings):
"""Pinecone model settings

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
)
from semantic_kernel.memory.memory_record import MemoryRecord
from semantic_kernel.memory.memory_store_base import MemoryStoreBase
from semantic_kernel.utils.experimental_decorator import experimental_class

# Limitation based on pgvector documentation https://github.com/pgvector/pgvector#what-if-i-want-to-index-vectors-with-more-than-2000-dimensions
MAX_DIMENSIONALITY = 2000
Expand All @@ -28,6 +29,7 @@
logger: logging.Logger = logging.getLogger(__name__)


@experimental_class
class PostgresMemoryStore(MemoryStoreBase):
"""A memory store that uses Postgres with pgvector as the backend."""

Expand Down
Loading
Loading