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,32 @@
# Copyright (c) Microsoft. All rights reserved.
from pytest import fixture
@fixture()
def onnx_unit_test_env(monkeypatch, exclude_list, override_env_param_dict):
"""Fixture to set environment variables for OnnxGenAISettings."""
if exclude_list is None:
exclude_list = []
if override_env_param_dict is None:
override_env_param_dict = {}
env_vars = {
"ONNX_GEN_AI_CHAT_MODEL_FOLDER": "test",
"ONNX_GEN_AI_TEXT_MODEL_FOLDER": "test",
}
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
gen_ai_config = {"model": {"test": "test"}}
gen_ai_config_vision = {"model": {"vision": "test"}}
@@ -0,0 +1,187 @@
# Copyright (c) Microsoft. All rights reserved.
import json
import os
from unittest.mock import MagicMock, mock_open, patch
import pytest
from semantic_kernel.connectors.ai.onnx import OnnxGenAIChatCompletion, OnnxGenAIPromptExecutionSettings, ONNXTemplate
from semantic_kernel.contents import AuthorRole, ChatHistory, ChatMessageContent, ImageContent
from semantic_kernel.exceptions import ServiceInitializationError, ServiceInvalidExecutionSettingsError
from semantic_kernel.kernel import Kernel
from tests.unit.connectors.ai.onnx.conftest import gen_ai_config, gen_ai_config_vision
@patch("builtins.open", new_callable=mock_open, read_data=json.dumps(gen_ai_config))
@patch("onnxruntime_genai.Model")
@patch("onnxruntime_genai.Tokenizer")
def test_onnx_chat_completion_with_valid_env_variable(gen_ai_config, model, tokenizer, onnx_unit_test_env):
service = OnnxGenAIChatCompletion(template=ONNXTemplate.PHI3, env_file_path="test.env")
assert not service.enable_multi_modality
@patch("builtins.open", new_callable=mock_open, read_data=json.dumps(gen_ai_config_vision))
@patch("onnxruntime_genai.Model")
@patch("onnxruntime_genai.Tokenizer")
def test_onnx_chat_completion_with_vision_valid_env_variable(
gen_ai_vision_config, model, tokenizer, onnx_unit_test_env
):
service = OnnxGenAIChatCompletion(template=ONNXTemplate.PHI3, env_file_path="test.env")
assert service.enable_multi_modality
@patch("builtins.open", new_callable=mock_open, read_data=json.dumps(gen_ai_config))
@patch("onnxruntime_genai.Model")
@patch("onnxruntime_genai.Tokenizer")
def test_onnx_chat_completion_with_valid_parameter(gen_ai_config, model, tokenizer):
assert OnnxGenAIChatCompletion(ai_model_path="/valid_path", template=ONNXTemplate.PHI3)
@patch("builtins.open", new_callable=mock_open, read_data=json.dumps(gen_ai_config))
@patch("onnxruntime_genai.Model")
@patch("onnxruntime_genai.Tokenizer")
def test_onnx_chat_completion_with_str_template(gen_ai_config, model, tokenizer):
assert OnnxGenAIChatCompletion(ai_model_path="/valid_path", template="phi3")
def test_onnx_chat_completion_with_invalid_model():
with pytest.raises(ServiceInitializationError):
OnnxGenAIChatCompletion(
ai_model_path="/invalid_path",
template=ONNXTemplate.PHI3,
)
@patch("builtins.open", new_callable=mock_open, read_data=json.dumps(gen_ai_config_vision))
def test_onnx_chat_completion_with_multimodality_without_prompt_template(gen_ai_config_vision):
with pytest.raises(ServiceInitializationError):
OnnxGenAIChatCompletion()
def test_onnx_chat_completion_with_invalid_env_variable(onnx_unit_test_env):
with pytest.raises(ServiceInitializationError):
OnnxGenAIChatCompletion(
template=ONNXTemplate.PHI3,
)
@pytest.mark.parametrize("exclude_list", [["ONNX_GEN_AI_CHAT_MODEL_FOLDER"]], indirect=True)
def test_onnx_chat_completion_with_missing_ai_path(onnx_unit_test_env):
with pytest.raises(ServiceInitializationError):
OnnxGenAIChatCompletion(template=ONNXTemplate.PHI3, env_file_path="test.env")
@patch("builtins.open", new_callable=mock_open, read_data=json.dumps(gen_ai_config))
@patch("onnxruntime_genai.Model")
@patch("onnxruntime_genai.Tokenizer")
async def test_onnx_chat_completion(gen_ai_config, model, tokenizer):
generator_mock = MagicMock()
generator_mock.__aiter__.return_value = [["H"], ["e"], ["l"], ["l"], ["o"]]
chat_completion = OnnxGenAIChatCompletion(template=ONNXTemplate.PHI3, ai_model_path="test")
history = ChatHistory()
history.add_system_message("test")
history.add_user_message("test")
with patch.object(chat_completion, "_generate_next_token_async", return_value=generator_mock):
completed_text: ChatMessageContent = await chat_completion.get_chat_message_content(
prompt="test", chat_history=history, settings=OnnxGenAIPromptExecutionSettings(), kernel=Kernel()
)
assert str(completed_text) == "Hello"
@patch("builtins.open", new_callable=mock_open, read_data=json.dumps(gen_ai_config))
@patch("onnxruntime_genai.Model")
@patch("onnxruntime_genai.Tokenizer")
async def test_onnx_chat_completion_streaming(gen_ai_config, model, tokenizer):
generator_mock = MagicMock()
generator_mock.__aiter__.return_value = [["H"], ["e"], ["l"], ["l"], ["o"]]
chat_completion = OnnxGenAIChatCompletion(template=ONNXTemplate.PHI3, ai_model_path="test")
history = ChatHistory()
history.add_system_message("test")
history.add_user_message("test")
completed_text: str = ""
with patch.object(chat_completion, "_generate_next_token_async", return_value=generator_mock):
async for chunk in chat_completion.get_streaming_chat_message_content(
prompt="test", chat_history=history, settings=OnnxGenAIPromptExecutionSettings(), kernel=Kernel()
):
completed_text += str(chunk)
assert completed_text == "Hello"
@patch("onnxruntime_genai.Model")
def test_onnx_chat_get_image_history(model):
builtin_open = open # save the unpatched version
def patch_open(*args, **kwargs):
if "genai_config.json" in str(args[0]):
# mocked open for path "genai_config.json"
return mock_open(read_data=json.dumps(gen_ai_config_vision))(*args, **kwargs)
# unpatched version for every other path
return builtin_open(*args, **kwargs)
with patch("builtins.open", patch_open):
chat_completion = OnnxGenAIChatCompletion(
template=ONNXTemplate.PHI3,
ai_model_path="test",
)
image_content = ImageContent.from_image_path(
image_path=os.path.join(os.path.dirname(__file__), "../../../../../", "assets/sample_image.jpg")
)
history = ChatHistory()
history.add_system_message("test")
history.add_user_message("test")
history.add_message(
ChatMessageContent(
role=AuthorRole.USER,
items=[image_content],
),
)
last_image = chat_completion._get_images_from_history(history)
assert last_image == [image_content]
@patch("onnxruntime_genai.Model")
@patch("onnxruntime_genai.Tokenizer")
async def test_onnx_chat_get_image_history_with_not_multimodal(model, tokenizer):
builtin_open = open # save the unpatched version
def patch_open(*args, **kwargs):
if "genai_config.json" in str(args[0]):
# mocked open for path "genai_config.json"
return mock_open(read_data=json.dumps(gen_ai_config))(*args, **kwargs)
# unpatched version for every other path
return builtin_open(*args, **kwargs)
with patch("builtins.open", patch_open):
chat_completion = OnnxGenAIChatCompletion(
template=ONNXTemplate.PHI3,
ai_model_path="test",
)
image_content = ImageContent.from_image_path(
image_path=os.path.join(os.path.dirname(__file__), "../../../../../", "assets/sample_image.jpg")
)
history = ChatHistory()
history.add_system_message("test")
history.add_user_message("test")
history.add_message(
ChatMessageContent(
role=AuthorRole.USER,
items=[image_content],
),
)
with pytest.raises(ServiceInvalidExecutionSettingsError):
_ = await chat_completion._get_images_from_history(history)
@@ -0,0 +1,74 @@
# Copyright (c) Microsoft. All rights reserved.
import json
from unittest.mock import MagicMock, mock_open, patch
import pytest
from semantic_kernel.connectors.ai.onnx import OnnxGenAIPromptExecutionSettings, OnnxGenAITextCompletion # noqa: E402
from semantic_kernel.contents import TextContent
from semantic_kernel.exceptions import ServiceInitializationError
from tests.unit.connectors.ai.onnx.conftest import gen_ai_config
@patch("builtins.open", new_callable=mock_open, read_data=json.dumps(gen_ai_config))
@patch("onnxruntime_genai.Model")
@patch("onnxruntime_genai.Tokenizer")
def test_onnx_chat_completion_with_valid_env_variable(gen_ai_config, model, tokenizer, onnx_unit_test_env):
assert OnnxGenAITextCompletion(env_file_path="test.env")
@patch("builtins.open", new_callable=mock_open, read_data=json.dumps(gen_ai_config))
@patch("onnxruntime_genai.Model")
@patch("onnxruntime_genai.Tokenizer")
def test_onnx_chat_completion_with_valid_parameter(gen_ai_config, model, tokenizer):
assert OnnxGenAITextCompletion(ai_model_path="/valid_path")
def test_onnx_chat_completion_with_invalid_model():
with pytest.raises(ServiceInitializationError):
OnnxGenAITextCompletion(ai_model_path="/invalid_path")
def test_onnx_chat_completion_with_invalid_env_variable(onnx_unit_test_env):
with pytest.raises(ServiceInitializationError):
OnnxGenAITextCompletion()
@pytest.mark.parametrize("exclude_list", [["ONNX_GEN_AI_TEXT_MODEL_FOLDER"]], indirect=True)
def test_onnx_chat_completion_with_missing_ai_path(onnx_unit_test_env):
with pytest.raises(ServiceInitializationError):
OnnxGenAITextCompletion(env_file_path="test.env")
@patch("builtins.open", new_callable=mock_open, read_data=json.dumps(gen_ai_config))
@patch("onnxruntime_genai.Model")
@patch("onnxruntime_genai.Tokenizer")
async def test_onnx_text_completion(gen_ai_config, model, tokenizer):
generator_mock = MagicMock()
generator_mock.__aiter__.return_value = [["H"], ["e"], ["l"], ["l"], ["o"]]
text_completion = OnnxGenAITextCompletion(ai_model_path="test")
with patch.object(text_completion, "_generate_next_token_async", return_value=generator_mock):
completed_text: TextContent = await text_completion.get_text_content(
prompt="test", settings=OnnxGenAIPromptExecutionSettings()
)
assert completed_text.text == "Hello"
@patch("builtins.open", new_callable=mock_open, read_data=json.dumps(gen_ai_config))
@patch("onnxruntime_genai.Model")
@patch("onnxruntime_genai.Tokenizer")
async def test_onnx_text_completion_streaming(gen_ai_config, model, tokenizer):
generator_mock = MagicMock()
generator_mock.__aiter__.return_value = [["H"], ["e"], ["l"], ["l"], ["o"]]
text_completion = OnnxGenAITextCompletion(ai_model_path="test")
completed_text: str = ""
with patch.object(text_completion, "_generate_next_token_async", return_value=generator_mock):
async for chunk in text_completion.get_streaming_text_content(
prompt="test", settings=OnnxGenAIPromptExecutionSettings()
):
completed_text += chunk.text
assert completed_text == "Hello"
@@ -0,0 +1,132 @@
# Copyright (c) Microsoft. All rights reserved.
from semantic_kernel.connectors.ai.onnx.utils import (
gemma_template,
llama_template,
phi3_template,
phi3v_template,
phi4_template,
phi4mm_template,
)
from semantic_kernel.contents import AudioContent, AuthorRole, ChatHistory, ImageContent, TextContent
def test_phi3v_template_with_text_and_image():
history = ChatHistory(
messages=[
{"role": AuthorRole.SYSTEM, "content": "System message"},
{
"role": AuthorRole.USER,
"items": [TextContent(text="User text message"), ImageContent(url="http://example.com/image.png")],
},
{"role": AuthorRole.ASSISTANT, "content": "Assistant message"},
]
)
expected_output = (
"<|system|>\nSystem message<|end|>\n"
"<|user|>\nUser text message<|end|>\n"
"<|image_1|>\n"
"<|assistant|>\nAssistant message<|end|>\n"
"<|assistant|>\n"
)
assert phi3v_template(history) == expected_output
def test_phi4mm_template_with_text_and_image():
history = ChatHistory(
messages=[
{"role": AuthorRole.SYSTEM, "content": "System message"},
{
"role": AuthorRole.USER,
"items": [
TextContent(text="User text message"),
ImageContent(url="http://example.com/image.png"),
AudioContent(url="http://example.com/audio.mp3"),
],
},
{"role": AuthorRole.ASSISTANT, "content": "Assistant message"},
]
)
expected_output = (
"<|system|>\nSystem message<|end|>\n"
"<|user|>\nUser text message<|end|>\n"
"<|image_1|>\n"
"<|audio_1|>\n"
"<|assistant|>\nAssistant message<|end|>\n"
"<|assistant|>\n"
)
assert phi4mm_template(history) == expected_output
def test_phi3_template_with_only_text():
history = ChatHistory(messages=[{"role": AuthorRole.USER, "items": [TextContent(text="User text message")]}])
expected_output = "<|user|>\nUser text message<|end|>\n<|assistant|>\n"
assert phi3_template(history) == expected_output
def test_phi4_template_with_only_text():
history = ChatHistory(messages=[{"role": AuthorRole.USER, "items": [TextContent(text="User text message")]}])
expected_output = "<|user|>\nUser text message<|end|>\n<|assistant|>\n"
assert phi4_template(history) == expected_output
def test_gemma_template_with_user_and_assistant_messages():
history = ChatHistory(
messages=[
{"role": AuthorRole.USER, "content": "User text message"},
{"role": AuthorRole.ASSISTANT, "content": "Assistant message"},
]
)
expected_output = (
"<bos>"
"<start_of_turn>user\nUser text message<end_of_turn>\n"
"<start_of_turn>model\nAssistant message<end_of_turn>\n"
"<start_of_turn>model\n"
)
assert gemma_template(history) == expected_output
def test_gemma_template_with_only_user_message():
history = ChatHistory(messages=[{"role": AuthorRole.USER, "content": "User text message"}])
expected_output = "<bos><start_of_turn>user\nUser text message<end_of_turn>\n<start_of_turn>model\n"
assert gemma_template(history) == expected_output
def test_llama_template_with_user_and_assistant_messages():
history = ChatHistory(
messages=[
{"role": AuthorRole.USER, "content": "User text message"},
{"role": AuthorRole.ASSISTANT, "content": "Assistant message"},
]
)
expected_output = (
"<|start_header_id|>user<|end_header_id|>\n\nUser text message<|eot_id|>"
"<|start_header_id|>assistant<|end_header_id|>\n\nAssistant message<|eot_id|>"
"<|start_header_id|>assistant<|end_header_id|>"
)
assert llama_template(history) == expected_output
def test_llama_template_with_only_user_message():
history = ChatHistory(messages=[{"role": AuthorRole.USER, "content": "User text message"}])
expected_output = (
"<|start_header_id|>user<|end_header_id|>\n\nUser text message<|eot_id|>"
"<|start_header_id|>assistant<|end_header_id|>"
)
assert llama_template(history) == expected_output
@@ -0,0 +1,84 @@
# Copyright (c) Microsoft. All rights reserved.
import pytest
from pydantic import ValidationError
from semantic_kernel.connectors.ai.onnx.onnx_gen_ai_prompt_execution_settings import (
OnnxGenAIPromptExecutionSettings,
)
from semantic_kernel.connectors.ai.prompt_execution_settings import PromptExecutionSettings
def test_default_onnx_chat_prompt_execution_settings():
settings = OnnxGenAIPromptExecutionSettings()
assert settings.temperature is None
assert settings.top_p is None
def test_custom_onnx_chat_prompt_execution_settings():
settings = OnnxGenAIPromptExecutionSettings(
temperature=0.5,
top_p=0.5,
max_length=128,
)
assert settings.temperature == 0.5
assert settings.top_p == 0.5
assert settings.max_length == 128
def test_onnx_chat_prompt_execution_settings_from_default_completion_config():
settings = PromptExecutionSettings(service_id="test_service")
chat_settings = OnnxGenAIPromptExecutionSettings.from_prompt_execution_settings(settings)
assert chat_settings.service_id == "test_service"
assert chat_settings.temperature is None
assert chat_settings.top_p is None
def test_onnx_chat_prompt_execution_settings_from_onnx_prompt_execution_settings():
chat_settings = OnnxGenAIPromptExecutionSettings(service_id="test_service", temperature=1.0)
new_settings = OnnxGenAIPromptExecutionSettings(service_id="test_2", temperature=0.0)
chat_settings.update_from_prompt_execution_settings(new_settings)
assert chat_settings.service_id == "test_2"
assert chat_settings.temperature == 0.0
def test_onnx_chat_prompt_execution_settings_from_custom_completion_config():
settings = PromptExecutionSettings(
service_id="test_service",
extension_data={
"temperature": 0.5,
"top_p": 0.5,
"max_length": 128,
},
)
chat_settings = OnnxGenAIPromptExecutionSettings.from_prompt_execution_settings(settings)
assert chat_settings.temperature == 0.5
assert chat_settings.top_p == 0.5
assert chat_settings.max_length == 128
def test_create_options():
settings = OnnxGenAIPromptExecutionSettings(
service_id="test_service",
extension_data={
"temperature": 0.5,
"top_p": 0.5,
"max_length": 128,
},
)
options = settings.prepare_settings_dict()
assert options["temperature"] == 0.5
assert options["top_p"] == 0.5
assert options["max_length"] == 128
def test_create_options_with_wrong_parameter():
with pytest.raises(ValidationError):
OnnxGenAIPromptExecutionSettings(
service_id="test_service",
function_choice_behavior="auto",
extension_data={
"temperature": 10.0,
"top_p": 0.5,
"max_length": 128,
},
)