Skip to content

Commit

Permalink
.Net Processes: fixing KernelProcessStateMetadata usage (microsoft#9598)
Browse files Browse the repository at this point in the history
### Description

- fixing definition of `KernelProcessStateMetadata` to be easier to
inherit/manage
- fixing missing plumbing of version in KernelState
- Updating Build interface in `ProcessStepBuilder` and `ProcessBuilder`

Fixes microsoft#9599 

### 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 😄
  • Loading branch information
esttenorio authored Nov 7, 2024
1 parent c539e8b commit 7404931
Show file tree
Hide file tree
Showing 17 changed files with 120 additions and 125 deletions.
Original file line number Diff line number Diff line change
@@ -1,47 +1,55 @@
{
"$type": "Process",
"stepsState": {
"FriedFishWithStatefulStepsProcess": {
"$type": "Process",
"stepsState": {
"GatherFriedFishIngredientsWithStockStep": {
"state": {
"IngredientsStock": 4
},
"id": "32301d167a604f7bb1b69663d8feafe6",
"$type": "Step",
"id": "2908f8c88cf0476a8e0075c3a8020d5d",
"name": "GatherFriedFishIngredientsWithStockStep",
"versionInfo": "GatherFishIngredient.V2"
"versionInfo": "GatherFishIngredient.V2",
"state": {
"IngredientsStock": 3
}
},
"CutFoodStep": {
"id": "3be68c614bc44bedb7bce0f002110968",
"$type": "Step",
"id": "014388cf0bbd41119b8730dfc4b0b459",
"name": "CutFoodStep",
"versionInfo": "CutFoodStep.V1"
},
"FryFoodStep": {
"id": "5f80945fafec4a0bbeccf3ff23a8c1a1",
"$type": "Step",
"id": "c55af0425d864c4e97b6ae67bd715480",
"name": "FryFoodStep",
"versionInfo": "FryFoodStep.V1"
}
},
"id": "c9d2e56dcc5a4b5ea73e05ae53635c90",
"id": "cab89a17aeae4b9a97568967dbf1ea47",
"name": "FriedFishWithStatefulStepsProcess",
"versionInfo": "FriedFishProcess.v1"
},
"AddBunsStep": {
"id": "ef113fc874b0473c9c275827effe8dd8",
"$type": "Step",
"id": "35d09b83dea24ddf8e0c24fbe6a3746c",
"name": "AddBunsStep",
"versionInfo": "v1"
},
"AddSpecialSauceStep": {
"id": "65a35f6dec6e45cab9e1b4df7d43a6bd",
"$type": "Step",
"id": "aa0d408976574afea94387e3da7ca111",
"name": "AddSpecialSauceStep",
"versionInfo": "v1"
},
"ExternalFriedFishStep": {
"id": "ab186a81480a45249cfff9e0c56319b8",
"$type": "Step",
"id": "2eda38b8ee8745a4ab8b21f4fa01d173",
"name": "ExternalFriedFishStep",
"versionInfo": "v1"
}
},
"id": "0de6d539-c1bf-44ad-816d-650231cd2034",
"id": "973b06f1-a522-4d2d-9e1c-ec45a07e275c",
"name": "FishSandwichWithStatefulStepsProcess",
"versionInfo": "FishSandwich.V1"
}
Original file line number Diff line number Diff line change
@@ -1,47 +1,55 @@
{
"$type": "Process",
"stepsState": {
"FriedFishWithStatefulStepsProcess": {
"$type": "Process",
"stepsState": {
"GatherFriedFishIngredientsWithStockStep": {
"$type": "Step",
"id": "2908f8c88cf0476a8e0075c3a8020d5d",
"name": "GatherFriedFishIngredientsWithStockStep",
"versionInfo": "GatherFishIngredient.V2",
"state": {
"IngredientsStock": 1
},
"id": "32301d167a604f7bb1b69663d8feafe6",
"name": "GatherFriedFishIngredientsWithStockStep",
"versionInfo": "GatherFishIngredient.V2"
}
},
"CutFoodStep": {
"id": "3be68c614bc44bedb7bce0f002110968",
"$type": "Step",
"id": "014388cf0bbd41119b8730dfc4b0b459",
"name": "CutFoodStep",
"versionInfo": "CutFoodStep.V1"
},
"FryFoodStep": {
"id": "5f80945fafec4a0bbeccf3ff23a8c1a1",
"$type": "Step",
"id": "c55af0425d864c4e97b6ae67bd715480",
"name": "FryFoodStep",
"versionInfo": "FryFoodStep.V1"
}
},
"id": "c9d2e56dcc5a4b5ea73e05ae53635c90",
"id": "cab89a17aeae4b9a97568967dbf1ea47",
"name": "FriedFishWithStatefulStepsProcess",
"versionInfo": "FriedFishProcess.v1"
},
"AddBunsStep": {
"id": "ef113fc874b0473c9c275827effe8dd8",
"$type": "Step",
"id": "35d09b83dea24ddf8e0c24fbe6a3746c",
"name": "AddBunsStep",
"versionInfo": "v1"
},
"AddSpecialSauceStep": {
"id": "65a35f6dec6e45cab9e1b4df7d43a6bd",
"$type": "Step",
"id": "aa0d408976574afea94387e3da7ca111",
"name": "AddSpecialSauceStep",
"versionInfo": "v1"
},
"ExternalFriedFishStep": {
"id": "ab186a81480a45249cfff9e0c56319b8",
"$type": "Step",
"id": "2eda38b8ee8745a4ab8b21f4fa01d173",
"name": "ExternalFriedFishStep",
"versionInfo": "v1"
}
},
"id": "0de6d539-c1bf-44ad-816d-650231cd2034",
"id": "973b06f1-a522-4d2d-9e1c-ec45a07e275c",
"name": "FishSandwichWithStatefulStepsProcess",
"versionInfo": "FishSandwich.V1"
}
Original file line number Diff line number Diff line change
@@ -1,25 +1,29 @@
{
"$type": "Process",
"stepsState": {
"GatherFriedFishIngredientsWithStockStep": {
"state": {
"IngredientsStock": 4
},
"id": "7d492b6c1ea9404b8adb4c9b0c8f7589",
"$type": "Step",
"id": "92a4cda38c7248648b0aa7ffaaa57f21",
"name": "GatherFriedFishIngredientsWithStockStep",
"versionInfo": "GatherFishIngredient.V2"
"versionInfo": "GatherFishIngredient.V2",
"state": {
"IngredientsStock": 3
}
},
"CutFoodStep": {
"id": "7c0d4dce18644abf92941ff2538806dc",
"$type": "Step",
"id": "7ace89e38e1c48b0b3a700b40d160c68",
"name": "CutFoodStep",
"versionInfo": "CutFoodStep.V1"
},
"FryFoodStep": {
"id": "de06bfb72a3d4f05ba3b4fd4ceb43e1f",
"$type": "Step",
"id": "09bc39ba6d9745439c7c792b8dac0af7",
"name": "FryFoodStep",
"versionInfo": "FryFoodStep.V1"
}
},
"id": "412f3ad1-d0fd-42f1-9c74-109cff87c75c",
"id": "669c5850-9efc-4585-b3f0-9291a4471887",
"name": "FriedFishWithStatefulStepsProcess",
"versionInfo": "FriedFishProcess.v1"
}
Original file line number Diff line number Diff line change
@@ -1,25 +1,29 @@
{
"$type": "Process",
"stepsState": {
"GatherFriedFishIngredientsWithStockStep": {
"$type": "Step",
"id": "92a4cda38c7248648b0aa7ffaaa57f21",
"name": "GatherFriedFishIngredientsWithStockStep",
"versionInfo": "GatherFishIngredient.V2",
"state": {
"IngredientsStock": 1
},
"id": "7d492b6c1ea9404b8adb4c9b0c8f7589",
"name": "GatherFriedFishIngredientsWithStockStep",
"versionInfo": "GatherFishIngredient.V2"
}
},
"CutFoodStep": {
"id": "7c0d4dce18644abf92941ff2538806dc",
"$type": "Step",
"id": "7ace89e38e1c48b0b3a700b40d160c68",
"name": "CutFoodStep",
"versionInfo": "CutFoodStep.V1"
},
"FryFoodStep": {
"id": "de06bfb72a3d4f05ba3b4fd4ceb43e1f",
"$type": "Step",
"id": "09bc39ba6d9745439c7c792b8dac0af7",
"name": "FryFoodStep",
"versionInfo": "FryFoodStep.V1"
}
},
"id": "412f3ad1-d0fd-42f1-9c74-109cff87c75c",
"id": "669c5850-9efc-4585-b3f0-9291a4471887",
"name": "FriedFishWithStatefulStepsProcess",
"versionInfo": "FriedFishProcess.v1"
}
Original file line number Diff line number Diff line change
@@ -1,25 +1,29 @@
{
"$type": "Process",
"stepsState": {
"GatherFriedFishIngredientsWithStockStep": {
"$type": "Step",
"id": "92a4cda38c7248648b0aa7ffaaa57f21",
"name": "GatherFriedFishIngredientsWithStockStep",
"versionInfo": "GatherFishIngredient.V2",
"state": {
"IngredientsStock": 0
},
"id": "7d492b6c1ea9404b8adb4c9b0c8f7589",
"name": "GatherFriedFishIngredientsWithStockStep",
"versionInfo": "GatherFishIngredient.V2"
}
},
"CutFoodStep": {
"id": "7c0d4dce18644abf92941ff2538806dc",
"$type": "Step",
"id": "7ace89e38e1c48b0b3a700b40d160c68",
"name": "CutFoodStep",
"versionInfo": "CutFoodStep.V1"
},
"FryFoodStep": {
"id": "de06bfb72a3d4f05ba3b4fd4ceb43e1f",
"$type": "Step",
"id": "09bc39ba6d9745439c7c792b8dac0af7",
"name": "FryFoodStep",
"versionInfo": "FryFoodStep.V1"
}
},
"id": "412f3ad1-d0fd-42f1-9c74-109cff87c75c",
"id": "669c5850-9efc-4585-b3f0-9291a4471887",
"name": "FriedFishWithStatefulStepsProcess",
"versionInfo": "FriedFishProcess.v1"
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public static void DumpProcessStateMetadataLocally(KernelProcessStateMetadata pr

using StreamReader reader = new(filepath);
var content = reader.ReadToEnd();
return JsonSerializer.Deserialize<KernelProcessStateMetadata>(content);
return JsonSerializer.Deserialize<KernelProcessStateMetadata>(content, s_jsonOptions);
}

private static string GetRepositoryProcessStateFilepath(string jsonRelativePath, bool checkFilepathExists = false)
Expand Down Expand Up @@ -62,7 +62,7 @@ private static void StoreProcessStateLocally(KernelProcessStateMetadata processS
throw new KernelException($"Filepath for process {processStateInfo.Name} does not have .json extension");
}

var content = JsonSerializer.Serialize(processStateInfo, s_jsonOptions);
var content = JsonSerializer.Serialize<KernelProcessStepStateMetadata>(processStateInfo, s_jsonOptions);
Console.WriteLine($"Process State: \n{content}");
Console.WriteLine($"Saving Process State Locally: \n{Path.GetFullPath(fullFilepath)}");
File.WriteAllText(fullFilepath, content);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ namespace Microsoft.SemanticKernel.Process.Models;
/// <summary>
/// Process state used for State Persistence serialization
/// </summary>
public record class KernelProcessStateMetadata : KernelProcessStepStateMetadata<object>
public sealed record class KernelProcessStateMetadata : KernelProcessStepStateMetadata
{
/// <summary>
/// Process State of Steps if provided
/// </summary>
[DataMember]
[JsonPropertyName("stepsState")]
public Dictionary<string, KernelProcessStateMetadata>? StepsState { get; set; }
public Dictionary<string, KernelProcessStepStateMetadata>? StepsState { get; set; } = null;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@

using System.Runtime.Serialization;
using System.Text.Json.Serialization;
using Microsoft.SemanticKernel.Process.Internal;

namespace Microsoft.SemanticKernel.Process.Models;

/// <summary>
/// Step state used for State Persistence serialization
/// </summary>
[JsonPolymorphic(TypeDiscriminatorPropertyName = "$type", UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToNearestAncestor)]
[JsonDerivedType(typeof(KernelProcessStepStateMetadata), typeDiscriminator: nameof(ProcessConstants.SupportedComponents.Step))]
[JsonDerivedType(typeof(KernelProcessStateMetadata), typeDiscriminator: nameof(ProcessConstants.SupportedComponents.Process))]
public record class KernelProcessStepStateMetadata
{
/// <summary>
Expand All @@ -33,17 +37,11 @@ public record class KernelProcessStepStateMetadata
[DataMember]
[JsonPropertyName("versionInfo")]
public string? VersionInfo { get; init; } = null;
}

/// <summary>
/// Step state used for State Persistence serialization for stateful steps
/// </summary>
public record class KernelProcessStepStateMetadata<TState> : KernelProcessStepStateMetadata where TState : class, new()
{
/// <summary>
/// The user-defined state object associated with the Step.
/// The user-defined state object associated with the Step (if the step is stateful)
/// </summary>
[DataMember]
[JsonPropertyName("state")]
public TState? State { get; set; } = null;
public object? State { get; set; } = null;
}
7 changes: 1 addition & 6 deletions dotnet/src/Experimental/Process.Core/Internal/EndStep.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,7 @@ internal override Dictionary<string, KernelFunctionMetadata> GetFunctionMetadata
return [];
}

internal override KernelProcessStepInfo BuildStep()
{
return this.BuildStep(null);
}

internal override KernelProcessStepInfo BuildStep(KernelProcessStepStateMetadata<object>? stateMetadata)
internal override KernelProcessStepInfo BuildStep(KernelProcessStepStateMetadata? stateMetadata = null)
{
// The end step has no state.
return new KernelProcessStepInfo(typeof(KernelProcessStepState), new KernelProcessStepState(ProcessConstants.EndStepName, version: ProcessConstants.InternalStepsVersion), []);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ private static KernelProcessStateMetadata SanitizeProcessStateMetadata(KernelPro
// version mismatch - check if migration logic in place
if (step is ProcessBuilder subprocessBuilder)
{
var sanitizedStepState = SanitizeProcessStateMetadata(savedStateMetadata, subprocessBuilder.Steps.ToList());
var sanitizedStepState = SanitizeProcessStateMetadata((KernelProcessStateMetadata)savedStateMetadata, subprocessBuilder.Steps.ToList());
sanitizedStateMetadata.StepsState[step.Name] = sanitizedStepState;
}
else if (false)
Expand All @@ -80,7 +80,7 @@ private static KernelProcessStateMetadata SanitizeProcessStateMetadata(KernelPro
else
{
// no compatible state found, migrating id only
sanitizedStateMetadata.StepsState[step.Name] = new KernelProcessStateMetadata()
sanitizedStateMetadata.StepsState[step.Name] = new KernelProcessStepStateMetadata()
{
Name = step.Name,
Id = step.Id,
Expand Down
22 changes: 3 additions & 19 deletions dotnet/src/Experimental/Process.Core/ProcessBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,31 +96,15 @@ internal override Dictionary<string, KernelFunctionMetadata> GetFunctionMetadata
/// </summary>
/// <param name="stateMetadata">State to apply to the step on the build process</param>
/// <returns></returns>
internal override KernelProcessStepInfo BuildStep(KernelProcessStepStateMetadata<object>? stateMetadata)
internal override KernelProcessStepInfo BuildStep(KernelProcessStepStateMetadata? stateMetadata = null)
{
// The step is a, process so we can return the step info directly.
if (stateMetadata is KernelProcessStateMetadata processState)
{
return this.BuildStep(processState);
return this.Build(processState);
}

return this.BuildStep();
}

/// <summary>
/// Build the subprocess step
/// </summary>
/// <param name="stateMetadata">State to apply to the step on the build process</param>
/// <returns></returns>
private KernelProcess BuildStep(KernelProcessStateMetadata? stateMetadata)
{
// The step is a process so we can return the step info directly.
return this.Build(stateMetadata);
}

internal override KernelProcessStepInfo BuildStep()
{
return this.Build(null);
return this.Build();
}

#region Public Interface
Expand Down
Loading

0 comments on commit 7404931

Please sign in to comment.