|  | 
| 1 | 1 | // Copyright (c) Microsoft. All rights reserved. | 
| 2 | 2 | 
 | 
|  | 3 | +using System; | 
|  | 4 | +using System.Collections.Generic; | 
| 3 | 5 | using System.Linq; | 
| 4 | 6 | using System.Text.Json; | 
| 5 | 7 | using Microsoft.SemanticKernel; | 
| @@ -82,4 +84,135 @@ public void FromExecutionSettingsShouldRestoreFunctionChoiceBehavior() | 
| 82 | 84 |         // Assert | 
| 83 | 85 |         Assert.Equal(functionChoiceBehavior, result.FunctionChoiceBehavior); | 
| 84 | 86 |     } | 
|  | 87 | + | 
|  | 88 | +    [Fact] | 
|  | 89 | +    public void PromptExecutionSettingsCloneWorksAsExpected() | 
|  | 90 | +    { | 
|  | 91 | +        // Arrange | 
|  | 92 | +        string configPayload = """ | 
|  | 93 | +        { | 
|  | 94 | +            "temperature": 0.5, | 
|  | 95 | +            "top_p": 0.9, | 
|  | 96 | +            "top_k": 100, | 
|  | 97 | +            "num_predict": 50, | 
|  | 98 | +            "stop": ["stop me"] | 
|  | 99 | +        } | 
|  | 100 | +        """; | 
|  | 101 | +        var executionSettings = JsonSerializer.Deserialize<OllamaPromptExecutionSettings>(configPayload); | 
|  | 102 | + | 
|  | 103 | +        // Act | 
|  | 104 | +        var clone = executionSettings!.Clone(); | 
|  | 105 | + | 
|  | 106 | +        // Assert | 
|  | 107 | +        Assert.NotNull(clone); | 
|  | 108 | +        Assert.IsType<OllamaPromptExecutionSettings>(clone); | 
|  | 109 | +        var ollamaClone = (OllamaPromptExecutionSettings)clone; | 
|  | 110 | +        Assert.Equal(executionSettings.ModelId, ollamaClone.ModelId); | 
|  | 111 | +        Assert.Equal(executionSettings.Temperature, ollamaClone.Temperature); | 
|  | 112 | +        Assert.Equal(executionSettings.TopP, ollamaClone.TopP); | 
|  | 113 | +        Assert.Equal(executionSettings.TopK, ollamaClone.TopK); | 
|  | 114 | +        Assert.Equal(executionSettings.NumPredict, ollamaClone.NumPredict); | 
|  | 115 | +        Assert.Equal(executionSettings.Stop, ollamaClone.Stop); | 
|  | 116 | +        Assert.Equivalent(executionSettings.ExtensionData, ollamaClone.ExtensionData); | 
|  | 117 | +    } | 
|  | 118 | + | 
|  | 119 | +    [Fact] | 
|  | 120 | +    public void ClonePreservesAllOllamaSpecificSettings() | 
|  | 121 | +    { | 
|  | 122 | +        // Arrange | 
|  | 123 | +        var testSettings = new OllamaPromptExecutionSettings | 
|  | 124 | +        { | 
|  | 125 | +            Temperature = 0.7f, | 
|  | 126 | +            TopP = 0.85f, | 
|  | 127 | +            TopK = 50, | 
|  | 128 | +            NumPredict = 100, | 
|  | 129 | +            Stop = new List<string> { "END", "STOP" }, | 
|  | 130 | +            ModelId = "llama2" | 
|  | 131 | +        }; | 
|  | 132 | + | 
|  | 133 | +        // Act | 
|  | 134 | +        var result = (OllamaPromptExecutionSettings)testSettings.Clone(); | 
|  | 135 | + | 
|  | 136 | +        // Assert | 
|  | 137 | +        Assert.NotNull(result); | 
|  | 138 | +        Assert.NotSame(testSettings, result); | 
|  | 139 | +        Assert.Equal(testSettings.Temperature, result.Temperature); | 
|  | 140 | +        Assert.Equal(testSettings.TopP, result.TopP); | 
|  | 141 | +        Assert.Equal(testSettings.TopK, result.TopK); | 
|  | 142 | +        Assert.Equal(testSettings.NumPredict, result.NumPredict); | 
|  | 143 | +        Assert.Equal(testSettings.ModelId, result.ModelId); | 
|  | 144 | +        Assert.NotSame(testSettings.Stop, result.Stop); | 
|  | 145 | +        Assert.Equal(testSettings.Stop, result.Stop); | 
|  | 146 | +    } | 
|  | 147 | + | 
|  | 148 | +    [Fact] | 
|  | 149 | +    public void CloneReturnsOllamaPromptExecutionSettingsType() | 
|  | 150 | +    { | 
|  | 151 | +        // This test verifies the exact issue from the bug report | 
|  | 152 | +        // Arrange | 
|  | 153 | +        var testSettings = new OllamaPromptExecutionSettings | 
|  | 154 | +        { | 
|  | 155 | +            Temperature = 0.7f, | 
|  | 156 | +            TopP = 0.9f, | 
|  | 157 | +            ServiceId = "test-service" | 
|  | 158 | +        }; | 
|  | 159 | + | 
|  | 160 | +        // Act | 
|  | 161 | +        var cloned = testSettings.Clone(); | 
|  | 162 | + | 
|  | 163 | +        // Assert - Should not throw InvalidCastException | 
|  | 164 | +        var result = (OllamaPromptExecutionSettings)cloned; | 
|  | 165 | +        Assert.NotNull(result); | 
|  | 166 | +        Assert.Equal(testSettings.Temperature, result.Temperature); | 
|  | 167 | +        Assert.Equal(testSettings.TopP, result.TopP); | 
|  | 168 | +        Assert.Equal(testSettings.ServiceId, result.ServiceId); | 
|  | 169 | +    } | 
|  | 170 | + | 
|  | 171 | +    [Fact] | 
|  | 172 | +    public void ClonePreservesServiceId() | 
|  | 173 | +    { | 
|  | 174 | +        // Arrange | 
|  | 175 | +        var testSettings = new OllamaPromptExecutionSettings | 
|  | 176 | +        { | 
|  | 177 | +            ServiceId = "my-ollama-service", | 
|  | 178 | +            ModelId = "llama2", | 
|  | 179 | +            Temperature = 0.8f | 
|  | 180 | +        }; | 
|  | 181 | + | 
|  | 182 | +        // Act | 
|  | 183 | +        var cloned = (OllamaPromptExecutionSettings)testSettings.Clone(); | 
|  | 184 | + | 
|  | 185 | +        // Assert | 
|  | 186 | +        Assert.Equal(testSettings.ServiceId, cloned.ServiceId); | 
|  | 187 | +        Assert.Equal(testSettings.ModelId, cloned.ModelId); | 
|  | 188 | +        Assert.Equal(testSettings.Temperature, cloned.Temperature); | 
|  | 189 | +    } | 
|  | 190 | + | 
|  | 191 | +    [Fact] | 
|  | 192 | +    public void PromptExecutionSettingsFreezeWorksAsExpected() | 
|  | 193 | +    { | 
|  | 194 | +        // Arrange | 
|  | 195 | +        var executionSettings = new OllamaPromptExecutionSettings | 
|  | 196 | +        { | 
|  | 197 | +            Temperature = 0.5f, | 
|  | 198 | +            TopP = 0.9f, | 
|  | 199 | +            TopK = 100, | 
|  | 200 | +            NumPredict = 50, | 
|  | 201 | +            Stop = new List<string> { "STOP" } | 
|  | 202 | +        }; | 
|  | 203 | + | 
|  | 204 | +        // Act | 
|  | 205 | +        executionSettings.Freeze(); | 
|  | 206 | + | 
|  | 207 | +        // Assert | 
|  | 208 | +        Assert.True(executionSettings.IsFrozen); | 
|  | 209 | +        Assert.Throws<InvalidOperationException>(() => executionSettings.Temperature = 1); | 
|  | 210 | +        Assert.Throws<InvalidOperationException>(() => executionSettings.TopP = 1); | 
|  | 211 | +        Assert.Throws<InvalidOperationException>(() => executionSettings.TopK = 1); | 
|  | 212 | +        Assert.Throws<InvalidOperationException>(() => executionSettings.NumPredict = 1); | 
|  | 213 | +        Assert.Throws<NotSupportedException>(() => executionSettings.Stop?.Add("END")); | 
|  | 214 | + | 
|  | 215 | +        executionSettings.Freeze(); // idempotent | 
|  | 216 | +        Assert.True(executionSettings.IsFrozen); | 
|  | 217 | +    } | 
| 85 | 218 | } | 
0 commit comments