chore: import upstream snapshot with attribution
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run

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,6 @@
# Copyright (c) Microsoft. All rights reserved.
from samples.getting_started_with_processes.step03.models.food_ingredients import FoodIngredients
from samples.getting_started_with_processes.step03.models.food_order_item import FoodItem
__all__ = ["FoodIngredients", "FoodItem"]
@@ -0,0 +1,15 @@
# Copyright (c) Microsoft. All rights reserved.
from enum import Enum
class FoodIngredients(str, Enum):
POTATOES = "Potatoes"
FISH = "Fish"
BUNS = "Buns"
SAUCE = "Sauce"
CONDIMENTS = "Condiments"
NONE = "None"
def to_friendly_string(self) -> str:
return self.value
@@ -0,0 +1,13 @@
# Copyright (c) Microsoft. All rights reserved.
from enum import Enum
class FoodItem(str, Enum):
POTATO_FRIES = "Potato Fries"
FRIED_FISH = "Fried Fish"
FISH_SANDWICH = "Fish Sandwich"
FISH_AND_CHIPS = "Fish & Chips"
def to_friendly_string(self) -> str:
return self.value
@@ -0,0 +1,7 @@
# Copyright (c) Microsoft. All rights reserved.
from samples.getting_started_with_processes.step03.processes.fish_and_chips_process import FishAndChipsProcess
from samples.getting_started_with_processes.step03.processes.fish_sandwich_process import FishSandwichProcess
from samples.getting_started_with_processes.step03.processes.fried_fish_process import FriedFishProcess
__all__ = ["FishAndChipsProcess", "FriedFishProcess", "FishSandwichProcess"]
@@ -0,0 +1,107 @@
# Copyright (c) Microsoft. All rights reserved.
import json
from enum import Enum
from samples.getting_started_with_processes.step03.processes.fried_fish_process import (
FriedFishProcess,
)
from samples.getting_started_with_processes.step03.processes.potato_fries_process import (
PotatoFriesProcess,
)
from samples.getting_started_with_processes.step03.steps.external_step import ExternalStep
from semantic_kernel.functions.kernel_function_decorator import kernel_function
from semantic_kernel.processes import ProcessBuilder
from semantic_kernel.processes.kernel_process import (
KernelProcessStep,
KernelProcessStepContext,
)
class AddFishAndChipsCondimentsStep(KernelProcessStep):
class Functions(Enum):
AddCondiments = "AddCondiments"
class OutputEvents(Enum):
CondimentsAdded = "CondimentsAdded"
@kernel_function(name=Functions.AddCondiments)
async def add_condiments(
self, context: KernelProcessStepContext, fish_actions: list[str], potato_actions: list[str]
):
print(
f"ADD_CONDIMENTS: Added condiments to Fish & Chips - "
f"Fish: {json.dumps(fish_actions)}, Potatoes: {json.dumps(potato_actions)}"
)
fish_actions.extend(potato_actions)
fish_actions.append("Condiments")
await context.emit_event(
process_event=self.OutputEvents.CondimentsAdded,
data=fish_actions,
)
class FishAndChipsProcess:
class ProcessEvents(Enum):
PrepareFishAndChips = "PrepareFishAndChips"
FishAndChipsReady = "FishAndChipsReady"
FishAndChipsIngredientOutOfStock = "FishAndChipsIngredientOutOfStock"
class ExternalFishAndChipsStep(ExternalStep):
def __init__(self) -> None:
super().__init__(FishAndChipsProcess.ProcessEvents.FishAndChipsReady)
@staticmethod
def create_process(process_name: str = "FishAndChipsProcess") -> ProcessBuilder:
process_builder = ProcessBuilder(process_name)
make_fish_step = process_builder.add_step_from_process(FriedFishProcess.create_process())
make_potato_step = process_builder.add_step_from_process(PotatoFriesProcess.create_process())
add_condiments_step = process_builder.add_step(AddFishAndChipsCondimentsStep)
external_step = process_builder.add_step(FishAndChipsProcess.ExternalFishAndChipsStep)
process_builder.on_input_event(FishAndChipsProcess.ProcessEvents.PrepareFishAndChips).send_event_to(
make_fish_step.where_input_event_is(FriedFishProcess.ProcessEvents.PrepareFriedFish)
).send_event_to(make_potato_step.where_input_event_is(PotatoFriesProcess.ProcessEvents.PreparePotatoFries))
make_fish_step.on_event(FriedFishProcess.ProcessEvents.FriedFishReady).send_event_to(
add_condiments_step, parameter_name="fishActions"
)
make_potato_step.on_event(PotatoFriesProcess.ProcessEvents.PotatoFriesReady).send_event_to(
add_condiments_step, parameter_name="potatoActions"
)
add_condiments_step.on_event(AddFishAndChipsCondimentsStep.OutputEvents.CondimentsAdded).send_event_to(
external_step
)
return process_builder
@staticmethod
def create_process_with_stateful_steps(
process_name: str = "FishAndChipsWithStatefulStepsProcess",
) -> ProcessBuilder:
process_builder = ProcessBuilder(process_name)
make_fish_step = process_builder.add_step_from_process(FriedFishProcess.create_process_with_stateful_steps_v1())
make_potato_step = process_builder.add_step_from_process(
PotatoFriesProcess.create_process_with_stateful_steps()
)
add_condiments_step = process_builder.add_step(AddFishAndChipsCondimentsStep)
external_step = process_builder.add_step(FishAndChipsProcess.ExternalFishAndChipsStep)
process_builder.on_input_event(FishAndChipsProcess.ProcessEvents.PrepareFishAndChips).send_event_to(
make_fish_step.where_input_event_is(FriedFishProcess.ProcessEvents.PrepareFriedFish)
).send_event_to(make_potato_step.where_input_event_is(PotatoFriesProcess.ProcessEvents.PreparePotatoFries))
make_fish_step.on_event(FriedFishProcess.ProcessEvents.FriedFishReady).send_event_to(
add_condiments_step, parameter_name="fishActions"
)
make_potato_step.on_event(PotatoFriesProcess.ProcessEvents.PotatoFriesReady).send_event_to(
add_condiments_step, parameter_name="potatoActions"
)
add_condiments_step.on_event(AddFishAndChipsCondimentsStep.OutputEvents.CondimentsAdded).send_event_to(
external_step
)
return process_builder
@@ -0,0 +1,129 @@
# Copyright (c) Microsoft. All rights reserved.
from enum import Enum
from samples.getting_started_with_processes.step03.processes.fried_fish_process import (
FriedFishProcess,
)
from samples.getting_started_with_processes.step03.steps.external_step import ExternalStep
from semantic_kernel.functions import kernel_function
from semantic_kernel.processes import ProcessBuilder
from semantic_kernel.processes.kernel_process import (
KernelProcessEventVisibility,
KernelProcessStep,
KernelProcessStepContext,
)
class AddBunStep(KernelProcessStep):
class Functions(Enum):
AddBuns = "AddBuns"
class OutputEvents(Enum):
BunsAdded = "BunsAdded"
@kernel_function(name=Functions.AddBuns)
async def slice_food(self, context: KernelProcessStepContext, food_actions: list[str]):
print(f"BUNS_ADDED_STEP: Buns added to ingredient {food_actions[0]}")
food_actions.append("Buns")
await context.emit_event(process_event=self.OutputEvents.BunsAdded, data=food_actions)
class AddSpecialSauceStep(KernelProcessStep):
class Functions(Enum):
AddSpecialSauce = "AddSpecialSauce"
class OutputEvents(Enum):
SpecialSauceAdded = "SpecialSauceAdded"
@kernel_function(name=Functions.AddSpecialSauce)
async def slice_food(self, context: KernelProcessStepContext, food_actions: list[str]):
print(f"SPECIAL_SAUCE_ADDED: Special sauce added to ingredient {food_actions[0]}")
food_actions.append("Sauce")
await context.emit_event(
process_event=self.OutputEvents.SpecialSauceAdded,
data=food_actions,
visibility=KernelProcessEventVisibility.Public,
)
class ExternalFriedFishStep(ExternalStep):
def __init__(self) -> None:
super().__init__(FishSandwichProcess.ProcessEvents.FishSandwichReady)
class FishSandwichProcess:
class ProcessEvents(Enum):
PrepareFishSandwich = "PrepareFishSandwich"
FishSandwichReady = "FishSandwichReady"
@staticmethod
def create_process(process_name: str = "FishSandwichProcess") -> ProcessBuilder:
process_builder = ProcessBuilder(process_name)
make_fried_fish_step = process_builder.add_step_from_process(FriedFishProcess.create_process())
add_buns_step = process_builder.add_step(AddBunStep)
add_sauce_step = process_builder.add_step(AddSpecialSauceStep)
external_step = process_builder.add_step(ExternalFriedFishStep)
process_builder.on_input_event(FishSandwichProcess.ProcessEvents.PrepareFishSandwich).send_event_to(
make_fried_fish_step.where_input_event_is(FriedFishProcess.ProcessEvents.PrepareFriedFish)
)
make_fried_fish_step.on_event(FriedFishProcess.ProcessEvents.FriedFishReady).send_event_to(add_buns_step)
add_buns_step.on_event(AddBunStep.OutputEvents.BunsAdded).send_event_to(add_sauce_step)
add_sauce_step.on_event(AddSpecialSauceStep.OutputEvents.SpecialSauceAdded).send_event_to(external_step)
return process_builder
@staticmethod
def create_process_with_stateful_steps_v1(
process_name: str = "FishSandwichWithStatefulStepsProcess",
) -> ProcessBuilder:
process_builder = ProcessBuilder(process_name, version="FishSandwich.V1")
make_fried_fish_step = process_builder.add_step_from_process(
FriedFishProcess.create_process_with_stateful_steps_v1()
)
add_buns_step = process_builder.add_step(AddBunStep)
add_sauce_step = process_builder.add_step(AddSpecialSauceStep)
external_step = process_builder.add_step(ExternalFriedFishStep)
process_builder.on_input_event(FishSandwichProcess.ProcessEvents.PrepareFishSandwich).send_event_to(
make_fried_fish_step.where_input_event_is(FriedFishProcess.ProcessEvents.PrepareFriedFish)
)
make_fried_fish_step.on_event(FriedFishProcess.ProcessEvents.FriedFishReady).send_event_to(add_buns_step)
add_buns_step.on_event(AddBunStep.OutputEvents.BunsAdded).send_event_to(add_sauce_step)
add_sauce_step.on_event(AddSpecialSauceStep.OutputEvents.SpecialSauceAdded).send_event_to(external_step)
return process_builder
@staticmethod
def create_process_with_stateful_steps_v2(
process_name: str = "FishSandwichWithStatefulStepsProcess",
) -> ProcessBuilder:
process_builder = ProcessBuilder(process_name, version="FishSandwich.V2")
make_fried_fish_step = process_builder.add_step_from_process(
FriedFishProcess.create_process_with_stateful_steps_v2(),
aliases=["FriedFishWithStatefulStepsProcess"],
)
add_buns_step = process_builder.add_step(AddBunStep)
add_sauce_step = process_builder.add_step(AddSpecialSauceStep)
external_step = process_builder.add_step(ExternalFriedFishStep)
process_builder.on_input_event(FishSandwichProcess.ProcessEvents.PrepareFishSandwich).send_event_to(
make_fried_fish_step.where_input_event_is(FriedFishProcess.ProcessEvents.PrepareFriedFish)
)
make_fried_fish_step.on_event(FriedFishProcess.ProcessEvents.FriedFishReady).send_event_to(add_buns_step)
add_buns_step.on_event(AddBunStep.OutputEvents.BunsAdded).send_event_to(add_sauce_step)
add_sauce_step.on_event(AddSpecialSauceStep.OutputEvents.SpecialSauceAdded).send_event_to(external_step)
return process_builder
@@ -0,0 +1,118 @@
# Copyright (c) Microsoft. All rights reserved.
from enum import Enum
from samples.getting_started_with_processes.step03.models import FoodIngredients
from samples.getting_started_with_processes.step03.steps import (
CutFoodStep,
FryFoodStep,
GatherIngredientsStep,
)
from samples.getting_started_with_processes.step03.steps.cut_food_with_sharpening_step import (
CutFoodWithSharpeningStep,
)
from samples.getting_started_with_processes.step03.steps.gather_ingredients_step import (
GatherIngredientsWithStockStep,
)
from semantic_kernel.processes import ProcessBuilder
from semantic_kernel.processes.kernel_process import (
kernel_process_step_metadata,
)
@kernel_process_step_metadata("GatherFishIngredient.V1")
class GatherFriedFishIngredientsStep(GatherIngredientsStep):
def __init__(self) -> None:
super().__init__(FoodIngredients.FISH)
@kernel_process_step_metadata("GatherFishIngredient.V2")
class GatherFriedFishIngredientsWithStockStep(GatherIngredientsWithStockStep):
def __init__(self) -> None:
super().__init__(FoodIngredients.FISH)
class FriedFishProcess:
class ProcessEvents(Enum):
PrepareFriedFish = "PrepareFriedFish"
FriedFishReady = FryFoodStep.OutputEvents.FriedFoodReady.value
@staticmethod
def create_process(process_name: str = "FriedFishProcess") -> ProcessBuilder:
process_builder = ProcessBuilder(process_name)
gather = process_builder.add_step(GatherFriedFishIngredientsStep)
chop = process_builder.add_step(CutFoodStep, name="chopStep")
fry = process_builder.add_step(FryFoodStep)
process_builder.on_input_event(FriedFishProcess.ProcessEvents.PrepareFriedFish).send_event_to(gather)
gather.on_event(GatherFriedFishIngredientsStep.OutputEvents.IngredientsGathered).send_event_to(
chop, function_name=CutFoodStep.Functions.ChopFood
)
chop.on_event(CutFoodStep.OutputEvents.ChoppingReady).send_event_to(fry)
fry.on_event(FryFoodStep.OutputEvents.FoodRuined).send_event_to(gather)
return process_builder
@staticmethod
def create_process_with_stateful_steps_v1(
process_name: str = "FriedFishWithStatefulStepsProcess",
) -> ProcessBuilder:
process_builder = ProcessBuilder(name=process_name, version="FriedFishProcess.v1")
gather = process_builder.add_step(GatherFriedFishIngredientsWithStockStep)
chop = process_builder.add_step(CutFoodWithSharpeningStep, name="chopStep")
fry = process_builder.add_step(FryFoodStep)
process_builder.on_input_event(FriedFishProcess.ProcessEvents.PrepareFriedFish).send_event_to(gather)
gather.on_event(GatherFriedFishIngredientsWithStockStep.OutputEvents.IngredientsGathered).send_event_to(
chop, function_name=CutFoodWithSharpeningStep.Functions.ChopFood
)
gather.on_event(GatherFriedFishIngredientsWithStockStep.OutputEvents.IngredientsOutOfStock).stop_process()
chop.on_event(CutFoodWithSharpeningStep.OutputEvents.ChoppingReady).send_event_to(fry)
chop.on_event(CutFoodWithSharpeningStep.OutputEvents.KnifeNeedsSharpening).send_event_to(
chop, function_name=CutFoodWithSharpeningStep.Functions.SharpenKnife
)
chop.on_event(CutFoodWithSharpeningStep.OutputEvents.KnifeSharpened).send_event_to(
chop, function_name=CutFoodWithSharpeningStep.Functions.ChopFood
)
fry.on_event(FryFoodStep.OutputEvents.FoodRuined).send_event_to(gather)
return process_builder
@staticmethod
def create_process_with_stateful_steps_v2(
process_name: str = "FriedFishWithStatefulStepsProcess",
) -> ProcessBuilder:
process_builder = ProcessBuilder(name=process_name, version="FriedFishProcess.v2")
gather = process_builder.add_step(
GatherFriedFishIngredientsWithStockStep,
name="gatherFishIngredientStep",
aliases=["GatherFriedFishIngredientsWithStockStep"],
)
chop = process_builder.add_step(
CutFoodWithSharpeningStep,
name="chopFishStep",
aliases=["CutFoodStep"],
)
fry = process_builder.add_step(FryFoodStep, name="fryFishStep", aliases=["FryFoodStep"])
process_builder.on_input_event(FriedFishProcess.ProcessEvents.PrepareFriedFish).send_event_to(gather)
gather.on_event(GatherFriedFishIngredientsWithStockStep.OutputEvents.IngredientsGathered).send_event_to(
chop, function_name=CutFoodWithSharpeningStep.Functions.ChopFood
)
gather.on_event(GatherFriedFishIngredientsWithStockStep.OutputEvents.IngredientsOutOfStock).stop_process()
chop.on_event(CutFoodWithSharpeningStep.OutputEvents.ChoppingReady).send_event_to(fry)
chop.on_event(CutFoodWithSharpeningStep.OutputEvents.KnifeNeedsSharpening).send_event_to(
chop, function_name=CutFoodWithSharpeningStep.Functions.SharpenKnife
)
chop.on_event(CutFoodWithSharpeningStep.OutputEvents.KnifeSharpened).send_event_to(
chop, function_name=CutFoodWithSharpeningStep.Functions.ChopFood
)
fry.on_event(FryFoodStep.OutputEvents.FoodRuined).send_event_to(gather)
return process_builder
@@ -0,0 +1,83 @@
# Copyright (c) Microsoft. All rights reserved.
from enum import Enum
from samples.getting_started_with_processes.step03.models.food_ingredients import FoodIngredients
from samples.getting_started_with_processes.step03.steps.cut_food_step import CutFoodStep
from samples.getting_started_with_processes.step03.steps.cut_food_with_sharpening_step import CutFoodWithSharpeningStep
from samples.getting_started_with_processes.step03.steps.fry_food_step import FryFoodStep
from samples.getting_started_with_processes.step03.steps.gather_ingredients_step import (
GatherIngredientsStep,
GatherIngredientsWithStockStep,
)
from semantic_kernel.processes import ProcessBuilder
class GatherPotatoFriesIngredientsStep(GatherIngredientsStep):
def __init__(self):
super().__init__(FoodIngredients.POTATOES)
class GatherPotatoFriesIngredientsWithStockStep(GatherIngredientsWithStockStep):
def __init__(self):
super().__init__(FoodIngredients.POTATOES)
class PotatoFriesProcess:
class ProcessEvents(Enum):
PreparePotatoFries = "PreparePotatoFries"
PotatoFriesReady = FryFoodStep.OutputEvents.FriedFoodReady.value
@staticmethod
def create_process(process_name: str = "PotatoFriesProcess"):
process_builder = ProcessBuilder(process_name)
gather_ingredients_step = process_builder.add_step(GatherPotatoFriesIngredientsStep)
slice_step = process_builder.add_step(CutFoodStep, name="sliceStep")
fry_step = process_builder.add_step(FryFoodStep)
process_builder.on_input_event(PotatoFriesProcess.ProcessEvents.PreparePotatoFries).send_event_to(
gather_ingredients_step
)
gather_ingredients_step.on_event(
GatherPotatoFriesIngredientsStep.OutputEvents.IngredientsGathered
).send_event_to(slice_step, function_name=CutFoodStep.Functions.SliceFood)
slice_step.on_event(CutFoodStep.OutputEvents.SlicingReady).send_event_to(fry_step)
fry_step.on_event(FryFoodStep.OutputEvents.FoodRuined).send_event_to(gather_ingredients_step)
return process_builder
@staticmethod
def create_process_with_stateful_steps(process_name: str = "PotatoFriesWithStatefulStepsProcess"):
process_builder = ProcessBuilder(process_name)
gather_ingredients_step = process_builder.add_step(GatherPotatoFriesIngredientsWithStockStep)
slice_step = process_builder.add_step(CutFoodWithSharpeningStep, name="sliceStep")
fry_step = process_builder.add_step(FryFoodStep)
process_builder.on_input_event(PotatoFriesProcess.ProcessEvents.PreparePotatoFries).send_event_to(
gather_ingredients_step
)
gather_ingredients_step.on_event(
GatherPotatoFriesIngredientsWithStockStep.OutputEvents.IngredientsGathered
).send_event_to(slice_step, function_name=CutFoodWithSharpeningStep.Functions.SliceFood)
gather_ingredients_step.on_event(
GatherPotatoFriesIngredientsWithStockStep.OutputEvents.IngredientsOutOfStock
).stop_process()
slice_step.on_event(CutFoodWithSharpeningStep.OutputEvents.SlicingReady).send_event_to(fry_step)
slice_step.on_event(CutFoodWithSharpeningStep.OutputEvents.KnifeNeedsSharpening).send_event_to(
slice_step, function_name=CutFoodWithSharpeningStep.Functions.SharpenKnife
)
slice_step.on_event(CutFoodWithSharpeningStep.OutputEvents.KnifeSharpened).send_event_to(
slice_step, function_name=CutFoodWithSharpeningStep.Functions.SliceFood
)
fry_step.on_event(FryFoodStep.OutputEvents.FoodRuined).send_event_to(gather_ingredients_step)
return process_builder
@@ -0,0 +1,122 @@
# Copyright (c) Microsoft. All rights reserved.
from enum import Enum
from samples.getting_started_with_processes.step03.models.food_order_item import FoodItem
from samples.getting_started_with_processes.step03.processes.fish_and_chips_process import FishAndChipsProcess
from samples.getting_started_with_processes.step03.processes.fish_sandwich_process import FishSandwichProcess
from samples.getting_started_with_processes.step03.processes.fried_fish_process import FriedFishProcess
from samples.getting_started_with_processes.step03.processes.potato_fries_process import PotatoFriesProcess
from samples.getting_started_with_processes.step03.steps.external_step import ExternalStep
from semantic_kernel.functions import kernel_function
from semantic_kernel.processes import ProcessBuilder
from semantic_kernel.processes.kernel_process import KernelProcessStep, KernelProcessStepContext
class PackOrderStep(KernelProcessStep):
class Functions(Enum):
PackFood = "PackFood"
class OutputEvents(Enum):
FoodPacked = "FoodPacked"
@kernel_function(name=Functions.PackFood)
async def pack_food(self, context: KernelProcessStepContext, food_actions: list[str]):
print(f"PACKING_FOOD: Food {food_actions[0]} Packed! - {food_actions}")
await context.emit_event(process_event=PackOrderStep.OutputEvents.FoodPacked)
class ExternalSingleOrderStep(ExternalStep):
def __init__(self):
super().__init__(SingleFoodItemProcess.ProcessEvents.SingleOrderReady)
class DispatchSingleOrderStep(KernelProcessStep):
class Functions(Enum):
PrepareSingleOrder = "PrepareSingleOrder"
class OutputEvents(Enum):
PrepareFries = "PrepareFries"
PrepareFriedFish = "PrepareFriedFish"
PrepareFishSandwich = "PrepareFishSandwich"
PrepareFishAndChips = "PrepareFishAndChips"
@kernel_function(name=Functions.PrepareSingleOrder)
async def dispatch_single_order(self, context: KernelProcessStepContext, food_item: FoodItem):
food_name = food_item.to_friendly_string()
print(f"DISPATCH_SINGLE_ORDER: Dispatching '{food_name}'!")
food_actions = []
if food_item == FoodItem.POTATO_FRIES:
await context.emit_event(process_event=DispatchSingleOrderStep.OutputEvents.PrepareFries, data=food_actions)
elif food_item == FoodItem.FRIED_FISH:
await context.emit_event(
process_event=DispatchSingleOrderStep.OutputEvents.PrepareFriedFish, data=food_actions
)
elif food_item == FoodItem.FISH_SANDWICH:
await context.emit_event(
process_event=DispatchSingleOrderStep.OutputEvents.PrepareFishSandwich, data=food_actions
)
elif food_item == FoodItem.FISH_AND_CHIPS:
await context.emit_event(
process_event=DispatchSingleOrderStep.OutputEvents.PrepareFishAndChips, data=food_actions
)
class SingleFoodItemProcess:
class ProcessEvents(Enum):
SingleOrderReceived = "SingleOrderReceived"
SingleOrderReady = "SingleOrderReady"
@staticmethod
def create_process(process_name: str = "SingleFoodItemProcess"):
process_builder = ProcessBuilder(process_name)
dispatch_order_step = process_builder.add_step(DispatchSingleOrderStep)
make_fried_fish_step = process_builder.add_step_from_process(FriedFishProcess.create_process())
make_potato_fries_step = process_builder.add_step_from_process(PotatoFriesProcess.create_process())
make_fish_sandwich_step = process_builder.add_step_from_process(FishSandwichProcess.create_process())
make_fish_and_chips_step = process_builder.add_step_from_process(FishAndChipsProcess.create_process())
pack_order_step = process_builder.add_step(PackOrderStep)
external_step = process_builder.add_step(ExternalSingleOrderStep)
process_builder.on_input_event(SingleFoodItemProcess.ProcessEvents.SingleOrderReceived).send_event_to(
dispatch_order_step
)
dispatch_order_step.on_event(DispatchSingleOrderStep.OutputEvents.PrepareFriedFish).send_event_to(
make_fried_fish_step.where_input_event_is(FriedFishProcess.ProcessEvents.PrepareFriedFish)
)
dispatch_order_step.on_event(DispatchSingleOrderStep.OutputEvents.PrepareFries).send_event_to(
make_potato_fries_step.where_input_event_is(PotatoFriesProcess.ProcessEvents.PreparePotatoFries)
)
dispatch_order_step.on_event(DispatchSingleOrderStep.OutputEvents.PrepareFishSandwich).send_event_to(
make_fish_sandwich_step.where_input_event_is(FishSandwichProcess.ProcessEvents.PrepareFishSandwich)
)
dispatch_order_step.on_event(DispatchSingleOrderStep.OutputEvents.PrepareFishAndChips).send_event_to(
make_fish_and_chips_step.where_input_event_is(FishAndChipsProcess.ProcessEvents.PrepareFishAndChips)
)
make_fried_fish_step.on_event(FriedFishProcess.ProcessEvents.FriedFishReady).send_event_to(pack_order_step)
make_potato_fries_step.on_event(PotatoFriesProcess.ProcessEvents.PotatoFriesReady).send_event_to(
pack_order_step
)
make_fish_sandwich_step.on_event(FishSandwichProcess.ProcessEvents.FishSandwichReady).send_event_to(
pack_order_step
)
make_fish_and_chips_step.on_event(FishAndChipsProcess.ProcessEvents.FishAndChipsReady).send_event_to(
pack_order_step
)
pack_order_step.on_event(PackOrderStep.OutputEvents.FoodPacked).send_event_to(external_step)
return process_builder
@@ -0,0 +1,60 @@
{
"$type": "Process",
"id": "612ad7ba84ea4b4593cfccd0092bc429",
"name": "FishSandwichWithStatefulStepsProcess",
"versionInfo": "FishSandwich.V1",
"stepsState": {
"FriedFishWithStatefulStepsProcess": {
"$type": "Process",
"id": "1632a2f0cec7417b825768625f8444e7",
"name": "FriedFishWithStatefulStepsProcess",
"versionInfo": "FriedFishProcess.v1",
"stepsState": {
"GatherFriedFishIngredientsWithStockStep": {
"$type": "Step",
"id": "b146fbb374ae4751b8e2bdf029b6cd69",
"name": "GatherFriedFishIngredientsWithStockStep",
"versionInfo": "GatherFishIngredient.V2",
"state": {
"IngredientsStock": 3
}
},
"chopStep": {
"$type": "Step",
"id": "5be2e3825a7948d9bfa494aa907166d3",
"name": "chopStep",
"versionInfo": "CutFoodStep.V2",
"state": {
"KnifeSharpness": 3,
"NeedsSharpeningLimit": 3,
"SharpeningBoost": 5
}
},
"FryFoodStep": {
"$type": "Step",
"id": "a975d1b33c634cf093179fea9d271b84",
"name": "FryFoodStep",
"versionInfo": "FryFoodStep.V1"
}
}
},
"AddBunStep": {
"$type": "Step",
"id": "5f4f96f48a1b4e83b4101688550491d3",
"name": "AddBunStep",
"versionInfo": "v1"
},
"AddSpecialSauceStep": {
"$type": "Step",
"id": "67e4b77e63cb447ea774fe9665019e71",
"name": "AddSpecialSauceStep",
"versionInfo": "v1"
},
"ExternalFriedFishStep": {
"$type": "Step",
"id": "9ecebab987cf4667b9abe48640034707",
"name": "ExternalFriedFishStep",
"versionInfo": "v1"
}
}
}
@@ -0,0 +1,59 @@
{
"$type": "Process",
"name": "FishSandwichWithStatefulStepsProcess",
"versionInfo": "FishSandwich.V1",
"stepsState": {
"FriedFishWithStatefulStepsProcess": {
"$type": "Process",
"id": "d4dc8776d4574b95a4cc39e2e7667018",
"name": "FriedFishWithStatefulStepsProcess",
"versionInfo": "FriedFishProcess.v1",
"stepsState": {
"GatherFriedFishIngredientsWithStockStep": {
"$type": "Step",
"id": "94d2df838d314d4e8fd694398f6a3ada",
"name": "GatherFriedFishIngredientsWithStockStep",
"versionInfo": "GatherFishIngredient.V2",
"state": {
"IngredientsStock": 1
}
},
"chopStep": {
"$type": "Step",
"id": "467e52a1187f497d865b897d56b68db0",
"name": "chopStep",
"versionInfo": "CutFoodStep.V2",
"state": {
"KnifeSharpness": 5,
"NeedsSharpeningLimit": 3,
"SharpeningBoost": 5
}
},
"FryFoodStep": {
"$type": "Step",
"id": "ba3a93b5885e4b75af0c9a46015e3e66",
"name": "FryFoodStep",
"versionInfo": "FryFoodStep.V1"
}
}
},
"AddBunStep": {
"$type": "Step",
"id": "36448a39e963432caded6ca3206849e6",
"name": "AddBunStep",
"versionInfo": "v1"
},
"AddSpecialSauceStep": {
"$type": "Step",
"id": "d1ac856e1e5f49e6a9f389c870bc9aa1",
"name": "AddSpecialSauceStep",
"versionInfo": "v1"
},
"ExternalFriedFishStep": {
"$type": "Step",
"id": "ea1a9b2f08d7407b84093ffb4f34daca",
"name": "ExternalFriedFishStep",
"versionInfo": "v1"
}
}
}
@@ -0,0 +1,34 @@
{
"$type": "Process",
"id": "e0dd9eb8160e480daaaef49a14bcf551",
"name": "FriedFishWithStatefulStepsProcess",
"versionInfo": "FriedFishProcess.v1",
"stepsState": {
"GatherFriedFishIngredientsWithStockStep": {
"$type": "Step",
"id": "480bfb877a9c48a599e956312747879b",
"name": "GatherFriedFishIngredientsWithStockStep",
"versionInfo": "GatherFishIngredient.V2",
"state": {
"IngredientsStock": 4
}
},
"chopStep": {
"$type": "Step",
"id": "63b794c970ca4bf4816545bff7395c1c",
"name": "chopStep",
"versionInfo": "CutFoodStep.V2",
"state": {
"KnifeSharpness": 4,
"NeedsSharpeningLimit": 3,
"SharpeningBoost": 5
}
},
"FryFoodStep": {
"$type": "Step",
"id": "66545dcca7394071a434ec1e66116517",
"name": "FryFoodStep",
"versionInfo": "FryFoodStep.V1"
}
}
}
@@ -0,0 +1,33 @@
{
"$type": "Process",
"name": "FriedFishWithStatefulStepsProcess",
"versionInfo": "FriedFishProcess.v1",
"stepsState": {
"GatherFriedFishIngredientsWithStockStep": {
"$type": "Step",
"id": "9f4974949a2e4a54a67ccaf83ca4396b",
"name": "GatherFriedFishIngredientsWithStockStep",
"versionInfo": "GatherFishIngredient.V2",
"state": {
"IngredientsStock": 1
}
},
"chopStep": {
"$type": "Step",
"id": "c6669a103319475c92cdfc10aa30548a",
"name": "chopStep",
"versionInfo": "CutFoodStep.V2",
"state": {
"KnifeSharpness": 5,
"NeedsSharpeningLimit": 3,
"SharpeningBoost": 5
}
},
"FryFoodStep": {
"$type": "Step",
"id": "bd9f5eb584bc40bcbb3c79d9565efd86",
"name": "FryFoodStep",
"versionInfo": "FryFoodStep.V1"
}
}
}
@@ -0,0 +1,33 @@
{
"$type": "Process",
"name": "FriedFishWithStatefulStepsProcess",
"versionInfo": "FriedFishProcess.v1",
"stepsState": {
"GatherFriedFishIngredientsWithStockStep": {
"$type": "Step",
"id": "9f4974949a2e4a54a67ccaf83ca4396b",
"name": "GatherFriedFishIngredientsWithStockStep",
"versionInfo": "GatherFishIngredient.V2",
"state": {
"IngredientsStock": 0
}
},
"chopStep": {
"$type": "Step",
"id": "c6669a103319475c92cdfc10aa30548a",
"name": "chopStep",
"versionInfo": "CutFoodStep.V2",
"state": {
"KnifeSharpness": 5,
"NeedsSharpeningLimit": 3,
"SharpeningBoost": 5
}
},
"FryFoodStep": {
"$type": "Step",
"id": "bd9f5eb584bc40bcbb3c79d9565efd86",
"name": "FryFoodStep",
"versionInfo": "FryFoodStep.V1"
}
}
}
@@ -0,0 +1,444 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import json
from enum import Enum
from pathlib import Path
from samples.getting_started_with_processes.step03.processes.fish_and_chips_process import FishAndChipsProcess
from samples.getting_started_with_processes.step03.processes.fish_sandwich_process import FishSandwichProcess
from samples.getting_started_with_processes.step03.processes.fried_fish_process import FriedFishProcess
from samples.getting_started_with_processes.step03.processes.potato_fries_process import PotatoFriesProcess
from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion
from semantic_kernel.kernel import Kernel
from semantic_kernel.processes.kernel_process import KernelProcess, KernelProcessEvent, KernelProcessStateMetadata
from semantic_kernel.processes.local_runtime.local_kernel_process import start
from semantic_kernel.processes.process_builder import ProcessBuilder
"""
Demonstrate the creation of KernelProcess and eliciting different food related events.
This includes load/save steps for state management.
For visual reference of the processes used here check the diagram in:
https://github.com/microsoft/semantic-kernel/tree/main/python/samples/
getting_started_with_processes#step03b_food_ordering
"""
# region Helper Methods
def _create_kernel_with_chat_completion(service_id: str = "sample") -> Kernel:
kernel = Kernel()
kernel.add_service(OpenAIChatCompletion(service_id=service_id), overwrite=True)
return kernel
async def use_prepare_specific_product(process: ProcessBuilder, external_trigger_event: Enum):
"""
Helper function that:
1. Builds a KernelProcess from a ProcessBuilder
2. Starts it with the given external event
3. Waits for completion
"""
kernel = _create_kernel_with_chat_completion("sample")
kernel_process = process.build()
print(f"=== Start SK Process '{process.name}' ===")
async with await start(
kernel_process,
kernel,
KernelProcessEvent(id=external_trigger_event.value, data=[]),
):
pass
print(f"=== End SK Process '{process.name}' ===\n")
async def execute_process_with_state(
process: KernelProcess, kernel: Kernel, external_trigger_event: Enum, order_label: str
) -> KernelProcess:
"""
Starts the provided KernelProcess (with optional existing state),
returns the updated state after the run.
"""
print(f"=== {order_label} ===")
async with await start(
process,
kernel,
KernelProcessEvent(id=external_trigger_event.value, data=[]),
) as running_process:
return await running_process.get_state()
# endregion
# region Local JSON file handling for process state
BASE_DIR = Path(__file__).resolve().parent.parent
# Build the path to "step03/processes_states"
PROCESS_STATE_DIRECTORY = BASE_DIR / "step03" / "processes_states"
PROCESS_STATE_DIRECTORY.mkdir(parents=True, exist_ok=True)
def dump_process_state_metadata_locally(process_state: KernelProcessStateMetadata, json_filename: str) -> None:
"""
Saves the ProcessStateMetadata to a local JSON file in step03/processes_states,
relative to the current script's grandparent folder.
"""
file_path = PROCESS_STATE_DIRECTORY / json_filename
with open(file_path, "w", encoding="utf-8") as f:
json.dump(process_state.model_dump(exclude_none=True, by_alias=True, mode="json"), f, indent=4)
print(f"Process state saved to '{file_path.resolve()}'")
def load_process_state_metadata(json_filename: str) -> KernelProcessStateMetadata | None:
"""
Loads the ProcessStateMetadata from step03/processes_states if it exists.
Returns None if the file doesn't exist or fails to parse.
"""
file_path = PROCESS_STATE_DIRECTORY / json_filename
if not file_path.exists():
print(f"No such file: '{file_path.resolve()}'")
return None
try:
with open(file_path, encoding="utf-8") as f:
return KernelProcessStateMetadata.model_validate_json(f)
except Exception as ex:
print(f"Error reading state file '{file_path.resolve()}': {ex}")
return None
# endregion
# region Stateless Processes
async def use_prepare_fried_fish_process():
process = FriedFishProcess.create_process()
await use_prepare_specific_product(process, FriedFishProcess.ProcessEvents.PrepareFriedFish)
async def use_prepare_potato_fries_process():
process = PotatoFriesProcess.create_process()
await use_prepare_specific_product(process, PotatoFriesProcess.ProcessEvents.PreparePotatoFries)
async def use_prepare_fish_sandwich_process():
process = FishSandwichProcess.create_process()
await use_prepare_specific_product(process, FishSandwichProcess.ProcessEvents.PrepareFishSandwich)
async def use_prepare_fish_and_chips_process():
process = FishAndChipsProcess.create_process()
await use_prepare_specific_product(process, FishAndChipsProcess.ProcessEvents.PrepareFishAndChips)
# endregion
# region Stateful Processes
async def use_prepare_stateful_fried_fish_process_no_shared_state():
"""
Showcases building the stateful process multiple times.
Each new build has fresh/independent state.
"""
builder = FriedFishProcess.create_process_with_stateful_steps_v1()
event_name = FriedFishProcess.ProcessEvents.PrepareFriedFish
kernel = _create_kernel_with_chat_completion()
print(f"=== Start SK Process '{builder.name}' ===")
# Each build() -> new instance
await execute_process_with_state(builder.build(), kernel, event_name, "Order 1")
await execute_process_with_state(builder.build(), kernel, event_name, "Order 2")
print(f"=== End SK Process '{builder.name}' ===\n")
async def use_prepare_stateful_fried_fish_process_shared_state():
"""
Showcases building the stateful process once and reusing it,
meaning runs #2 and #3 continue from the prior run's state.
"""
builder = FriedFishProcess.create_process_with_stateful_steps_v2()
kernel = _create_kernel_with_chat_completion()
event_name = FriedFishProcess.ProcessEvents.PrepareFriedFish
single_process = builder.build() # one instance => shared state
print(f"=== Start SK Process '{builder.name}' ===")
await execute_process_with_state(single_process, kernel, event_name, "Order 1")
await execute_process_with_state(single_process, kernel, event_name, "Order 2")
await execute_process_with_state(single_process, kernel, event_name, "Order 3")
print(f"=== End SK Process '{builder.name}' ===\n")
async def use_prepare_stateful_potato_fries_process_shared_state():
builder = PotatoFriesProcess.create_process_with_stateful_steps()
kernel = _create_kernel_with_chat_completion()
event_name = PotatoFriesProcess.ProcessEvents.PreparePotatoFries
shared_process = builder.build()
print(f"=== Start SK Process '{builder.name}' ===")
await execute_process_with_state(shared_process, kernel, event_name, "Order 1")
await execute_process_with_state(shared_process, kernel, event_name, "Order 2")
await execute_process_with_state(shared_process, kernel, event_name, "Order 3")
print(f"=== End SK Process '{builder.name}' ===\n")
# endregion
# region Filenames for sample states
STATEFUL_FRIED_FISH_PROCESS_FILENAME = "FriedFishProcessStateSuccess.json"
STATEFUL_FRIED_FISH_LOWSTOCK_FILENAME = "FriedFishProcessStateSuccessLowStock.json"
STATEFUL_FRIED_FISH_NOSTOCK_FILENAME = "FriedFishProcessStateSuccessNoStock.json"
STATEFUL_FISH_SANDWICH_PROCESS_FILENAME = "FishSandwichStateProcessSuccess.json"
STATEFUL_FISH_SANDWICH_LOWSTOCK_FILENAME = "FishSandwichStateProcessSuccessLowStock.json"
# endregion
# region Reading/Writing process state from/to file
async def run_and_store_stateful_fried_fish_process_state():
"""
Runs the FriedFish stateful process once, then stores its state to JSON.
"""
kernel = _create_kernel_with_chat_completion()
builder = FriedFishProcess.create_process_with_stateful_steps_v1()
fried_fish_process = builder.build()
print("=== Start run_and_store_stateful_fried_fish_process_state ===")
final_state = await execute_process_with_state(
fried_fish_process, kernel, FriedFishProcess.ProcessEvents.PrepareFriedFish, "Order 1"
)
process_state_metadata = final_state.to_process_state_metadata()
dump_process_state_metadata_locally(process_state_metadata, STATEFUL_FRIED_FISH_PROCESS_FILENAME)
print("=== End run_and_store_stateful_fried_fish_process_state ===\n")
async def run_and_store_stateful_fish_sandwich_process_state():
"""
Runs the FishSandwich stateful process once, then stores its state to JSON.
"""
kernel = _create_kernel_with_chat_completion()
builder = FishSandwichProcess.create_process_with_stateful_steps_v1()
fish_sandwich_process = builder.build()
print("=== Start run_and_store_stateful_fish_sandwich_process_state ===")
final_state = await execute_process_with_state(
fish_sandwich_process, kernel, FishSandwichProcess.ProcessEvents.PrepareFishSandwich, "Order 1"
)
process_state_metadata = final_state.to_process_state_metadata()
dump_process_state_metadata_locally(process_state_metadata, STATEFUL_FISH_SANDWICH_PROCESS_FILENAME)
print("=== End run_and_store_stateful_fish_sandwich_process_state ===\n")
async def run_stateful_fried_fish_process_from_file():
loaded_metadata = KernelProcessStateMetadata.load_from_file(
json_filename=STATEFUL_FRIED_FISH_PROCESS_FILENAME, directory=PROCESS_STATE_DIRECTORY
)
if not loaded_metadata:
return
kernel = _create_kernel_with_chat_completion()
builder = FriedFishProcess.create_process_with_stateful_steps_v1()
process_from_file = builder.build(state_metadata=loaded_metadata)
print("=== Start run_stateful_fried_fish_process_from_file ===")
await execute_process_with_state(
process_from_file,
kernel,
FriedFishProcess.ProcessEvents.PrepareFriedFish,
"Using Stored State",
)
print("=== End run_stateful_fried_fish_process_from_file ===\n")
async def run_stateful_fried_fish_process_with_low_stock_from_file():
loaded_metadata = KernelProcessStateMetadata.load_from_file(
json_filename=STATEFUL_FRIED_FISH_LOWSTOCK_FILENAME, directory=PROCESS_STATE_DIRECTORY
)
if not loaded_metadata:
return
kernel = _create_kernel_with_chat_completion()
builder = FriedFishProcess.create_process_with_stateful_steps_v1()
process_from_file = builder.build(state_metadata=loaded_metadata)
print("=== Start run_stateful_fried_fish_process_with_low_stock_from_file ===")
await execute_process_with_state(
process_from_file,
kernel,
FriedFishProcess.ProcessEvents.PrepareFriedFish,
"Using Low Stock State",
)
print("=== End run_stateful_fried_fish_process_with_low_stock_from_file ===\n")
async def run_stateful_fried_fish_process_with_no_stock_from_file():
loaded_metadata = KernelProcessStateMetadata.load_from_file(
json_filename=STATEFUL_FRIED_FISH_NOSTOCK_FILENAME, directory=PROCESS_STATE_DIRECTORY
)
if not loaded_metadata:
return
kernel = _create_kernel_with_chat_completion()
builder = FriedFishProcess.create_process_with_stateful_steps_v1()
process_from_file = builder.build(state_metadata=loaded_metadata)
print("=== Start run_stateful_fried_fish_process_with_no_stock_from_file ===")
await execute_process_with_state(
process_from_file,
kernel,
FriedFishProcess.ProcessEvents.PrepareFriedFish,
"Using No Stock State",
)
print("=== End run_stateful_fried_fish_process_with_no_stock_from_file ===\n")
async def run_stateful_fish_sandwich_process_from_file():
loaded_metadata = KernelProcessStateMetadata.load_from_file(
json_filename=STATEFUL_FISH_SANDWICH_PROCESS_FILENAME, directory=PROCESS_STATE_DIRECTORY
)
if not loaded_metadata:
return
kernel = _create_kernel_with_chat_completion()
builder = FishSandwichProcess.create_process()
process_from_file = builder.build(state_metadata=loaded_metadata)
print("=== Start run_stateful_fish_sandwich_process_from_file ===")
await execute_process_with_state(
process_from_file,
kernel,
FishSandwichProcess.ProcessEvents.PrepareFishSandwich,
"Using Stored State",
)
print("=== End run_stateful_fish_sandwich_process_from_file ===\n")
async def run_stateful_fish_sandwich_process_with_low_stock_from_file():
loaded_metadata = KernelProcessStateMetadata.load_from_file(
json_filename=STATEFUL_FISH_SANDWICH_LOWSTOCK_FILENAME, directory=PROCESS_STATE_DIRECTORY
)
if not loaded_metadata:
return
kernel = _create_kernel_with_chat_completion()
builder = FishSandwichProcess.create_process()
process_from_file = builder.build(state_metadata=loaded_metadata)
print("=== Start run_stateful_fish_sandwich_process_with_low_stock_from_file ===")
await execute_process_with_state(
process_from_file,
kernel,
FishSandwichProcess.ProcessEvents.PrepareFishSandwich,
"Using Low Stock State",
)
print("=== End run_stateful_fish_sandwich_process_with_low_stock_from_file ===\n")
async def run_stateful_fried_fish_v2_with_low_stock_v1_state() -> None:
state_metadata = KernelProcessStateMetadata.load_from_file(
json_filename=STATEFUL_FRIED_FISH_LOWSTOCK_FILENAME, directory=PROCESS_STATE_DIRECTORY
)
if not state_metadata:
return
kernel = _create_kernel_with_chat_completion()
process = FriedFishProcess.create_process_with_stateful_steps_v2().build(state_metadata=state_metadata)
await execute_process_with_state(
process,
kernel,
FriedFishProcess.ProcessEvents.PrepareFriedFish,
"V2+low-stockV1state",
)
async def run_stateful_fish_sandwich_v2_with_low_stock_v1_state() -> None:
state_metadata = KernelProcessStateMetadata.load_from_file(
json_filename=STATEFUL_FISH_SANDWICH_LOWSTOCK_FILENAME, directory=PROCESS_STATE_DIRECTORY
)
if not state_metadata:
return
kernel = _create_kernel_with_chat_completion()
process = FishSandwichProcess.create_process_with_stateful_steps_v2().build(state_metadata=state_metadata)
await execute_process_with_state(
process,
kernel,
FishSandwichProcess.ProcessEvents.PrepareFishSandwich,
"V2+low-stockV1state",
)
# endregion
async def _make_low_and_no_stock_states() -> None:
"""Create the three 'low/no stock' JSON files expected by the sample."""
# ------------------------------------------------------------------ #
# 1. FriedFish — base stateful process (V1) #
# ------------------------------------------------------------------ #
ff_builder = FriedFishProcess.create_process_with_stateful_steps_v1()
ff_state_meta = ff_builder.build().to_process_state_metadata()
gather_meta = ff_state_meta.steps_state["GatherFriedFishIngredientsWithStockStep"]
gather_meta.state.ingredients_stock = 1
dump_process_state_metadata_locally(ff_state_meta, STATEFUL_FRIED_FISH_LOWSTOCK_FILENAME)
gather_meta.state.ingredients_stock = 0
dump_process_state_metadata_locally(ff_state_meta, STATEFUL_FRIED_FISH_NOSTOCK_FILENAME)
# ------------------------------------------------------------------ #
# 2. FishSandwich — nested FriedFish lowstock #
# ------------------------------------------------------------------ #
fs_builder = FishSandwichProcess.create_process_with_stateful_steps_v1()
fs_state_meta = fs_builder.build().to_process_state_metadata()
nested_ff_meta = fs_state_meta.steps_state["FriedFishWithStatefulStepsProcess"].steps_state[
"GatherFriedFishIngredientsWithStockStep"
]
nested_ff_meta.state.ingredients_stock = 1
dump_process_state_metadata_locally(fs_state_meta, STATEFUL_FISH_SANDWICH_LOWSTOCK_FILENAME)
async def main():
# Uncomment the following line to create the low/no stock states
# await _make_low_and_no_stock_states()
# Show basic usage of "stateless" processes
await use_prepare_fried_fish_process()
await use_prepare_potato_fries_process()
await use_prepare_fish_sandwich_process()
await use_prepare_fish_and_chips_process()
# # Show "stateful" processes, not storing or loading yet
await use_prepare_stateful_fried_fish_process_no_shared_state()
await use_prepare_stateful_fried_fish_process_shared_state()
await use_prepare_stateful_potato_fries_process_shared_state()
# Demonstration of storing then reloading state:
await run_and_store_stateful_fried_fish_process_state()
await run_and_store_stateful_fish_sandwich_process_state()
await run_stateful_fried_fish_process_from_file()
await run_stateful_fried_fish_process_with_low_stock_from_file()
await run_stateful_fried_fish_process_with_no_stock_from_file()
await run_stateful_fish_sandwich_process_from_file()
await run_stateful_fish_sandwich_process_with_low_stock_from_file()
await run_stateful_fried_fish_v2_with_low_stock_v1_state()
await run_stateful_fish_sandwich_v2_with_low_stock_v1_state()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,69 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from samples.getting_started_with_processes.step03.models.food_order_item import FoodItem
from samples.getting_started_with_processes.step03.processes.single_food_item_process import SingleFoodItemProcess
from semantic_kernel.connectors.ai.open_ai.services.open_ai_chat_completion import OpenAIChatCompletion
from semantic_kernel.kernel import Kernel
from semantic_kernel.processes.kernel_process.kernel_process_event import KernelProcessEvent
from semantic_kernel.processes.local_runtime.local_kernel_process import start
"""
Demonstrate the creation of KernelProcess and eliciting different food related events.
For visual reference of the processes used here check the diagram in:
https://github.com/microsoft/semantic-kernel/tree/main/python/samples/
getting_started_with_processes#step03b_food_ordering
"""
def _create_kernel_with_chat_completion(service_id: str) -> Kernel:
kernel = Kernel()
kernel.add_service(OpenAIChatCompletion(service_id=service_id), overwrite=True)
return kernel
async def use_prepare_food_order_process_single_item(food_item: FoodItem):
kernel = _create_kernel_with_chat_completion("sample")
kernel_process = SingleFoodItemProcess.create_process().build()
async with await start(
kernel_process,
kernel,
KernelProcessEvent(id=SingleFoodItemProcess.ProcessEvents.SingleOrderReceived, data=food_item),
) as running_process:
return running_process
async def use_single_order_fried_fish():
await use_prepare_food_order_process_single_item(FoodItem.FRIED_FISH)
async def use_single_order_potato_fries():
await use_prepare_food_order_process_single_item(FoodItem.POTATO_FRIES)
async def use_single_order_fish_sandwich():
await use_prepare_food_order_process_single_item(FoodItem.FISH_SANDWICH)
async def use_single_order_fish_and_chips():
await use_prepare_food_order_process_single_item(FoodItem.FISH_AND_CHIPS)
async def main():
order_methods = [
(use_single_order_fried_fish, "use_single_order_fried_fish"),
(use_single_order_potato_fries, "use_single_order_potato_fries"),
(use_single_order_fish_sandwich, "use_single_order_fish_sandwich"),
(use_single_order_fish_and_chips, "use_single_order_fish_and_chips"),
]
for method, name in order_methods:
print(f"=== Start '{name}' ===")
await method()
print(f"=== End '{name}' ===\n")
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,19 @@
# Copyright (c) Microsoft. All rights reserved.
from samples.getting_started_with_processes.step03.steps.cut_food_step import CutFoodStep
from samples.getting_started_with_processes.step03.steps.cut_food_with_sharpening_step import CutFoodWithSharpeningStep
from samples.getting_started_with_processes.step03.steps.external_step import ExternalStep
from samples.getting_started_with_processes.step03.steps.fry_food_step import FryFoodStep
from samples.getting_started_with_processes.step03.steps.gather_ingredients_step import (
GatherIngredientsStep,
GatherIngredientsWithStockStep,
)
__all__ = [
"ExternalStep",
"CutFoodStep",
"GatherIngredientsStep",
"GatherIngredientsWithStockStep",
"CutFoodWithSharpeningStep",
"FryFoodStep",
]
@@ -0,0 +1,38 @@
# Copyright (c) Microsoft. All rights reserved.
from enum import Enum
from semantic_kernel.functions import kernel_function
from semantic_kernel.processes.kernel_process import (
KernelProcessStep,
KernelProcessStepContext,
kernel_process_step_metadata,
)
@kernel_process_step_metadata("CutFoodStep.V1")
class CutFoodStep(KernelProcessStep):
class Functions(Enum):
ChopFood = "ChopFood"
SliceFood = "SliceFood"
class OutputEvents(Enum):
ChoppingReady = "ChoppingReady"
SlicingReady = "SlicingReady"
def get_action_string(self, food: str, action: str) -> str:
return f"{food}_{action}"
@kernel_function(name=Functions.ChopFood)
async def chop_food(self, context: KernelProcessStepContext, food_actions: list[str]):
food_to_be_cut = food_actions[0]
food_actions.append(self.get_action_string(food_to_be_cut, "chopped"))
print(f"CUTTING_STEP: Ingredient {food_to_be_cut} has been chopped!")
await context.emit_event(process_event=CutFoodStep.OutputEvents.ChoppingReady, data=food_actions)
@kernel_function(name=Functions.SliceFood)
async def slice_food(self, context: KernelProcessStepContext, food_actions: list[str]):
food_to_be_cut = food_actions[0]
food_actions.append(self.get_action_string(food_to_be_cut, "sliced"))
print(f"CUTTING_STEP: Ingredient {food_to_be_cut} has been sliced!")
await context.emit_event(process_event=CutFoodStep.OutputEvents.SlicingReady, data=food_actions)
@@ -0,0 +1,89 @@
# Copyright (c) Microsoft. All rights reserved.
from enum import Enum
from pydantic import Field
from semantic_kernel.functions import kernel_function
from semantic_kernel.kernel_pydantic import KernelBaseModel
from semantic_kernel.processes.kernel_process import (
KernelProcessStep,
KernelProcessStepContext,
KernelProcessStepState,
kernel_process_step_metadata,
)
class CutFoodWithSharpeningState(KernelBaseModel):
knife_sharpness: int = Field(default=5, alias="KnifeSharpness")
needs_sharpening_limit: int = Field(default=3, alias="NeedsSharpeningLimit")
sharpening_boost: int = Field(default=5, alias="SharpeningBoost")
@kernel_process_step_metadata("CutFoodStep.V2")
class CutFoodWithSharpeningStep(KernelProcessStep[CutFoodWithSharpeningState]):
class Functions(Enum):
ChopFood = "ChopFood"
SliceFood = "SliceFood"
SharpenKnife = "SharpenKnife"
class OutputEvents(Enum):
ChoppingReady = "ChoppingReady"
SlicingReady = "SlicingReady"
KnifeNeedsSharpening = "KnifeNeedsSharpening"
KnifeSharpened = "KnifeSharpened"
state: CutFoodWithSharpeningState | None = None
async def activate(self, state: KernelProcessStepState[CutFoodWithSharpeningState]) -> None:
self.state = state.state
def knife_needs_sharpening(self) -> bool:
return self.state.knife_sharpness == self.state.needs_sharpening_limit
def get_action_string(self, food: str, action: str) -> str:
return f"{food}_{action}"
@kernel_function(name=Functions.ChopFood)
async def chop_food(self, context: KernelProcessStepContext, food_actions: list[str]):
food_to_be_cut = food_actions[0]
if self.knife_needs_sharpening():
print(f"CUTTING_STEP: Dull knife, cannot chop {food_to_be_cut} - needs sharpening.")
await context.emit_event(
process_event=CutFoodWithSharpeningStep.OutputEvents.KnifeNeedsSharpening, data=food_actions
)
return
# Update knife sharpness
self.state.knife_sharpness -= 1
food_actions.append(self.get_action_string(food_to_be_cut, "chopped"))
print(
f"CUTTING_STEP: Ingredient {food_to_be_cut} has been chopped! - knife sharpness: {self.state.knife_sharpness}" # noqa: E501
)
await context.emit_event(process_event=CutFoodWithSharpeningStep.OutputEvents.ChoppingReady, data=food_actions)
@kernel_function(name=Functions.SliceFood)
async def slice_food(self, context: KernelProcessStepContext, food_actions: list[str]):
food_to_be_cut = food_actions[0]
if self.knife_needs_sharpening():
print(f"CUTTING_STEP: Dull knife, cannot slice {food_to_be_cut} - needs sharpening.")
await context.emit_event(
process_event=CutFoodWithSharpeningStep.OutputEvents.KnifeNeedsSharpening, data=food_actions
)
return
# Update knife sharpness
self.state.knife_sharpness -= 1
food_actions.append(self.get_action_string(food_to_be_cut, "sliced"))
print(
f"CUTTING_STEP: Ingredient {food_to_be_cut} has been sliced! - knife sharpness: {self.state.knife_sharpness}" # noqa: E501
)
await context.emit_event(process_event=CutFoodWithSharpeningStep.OutputEvents.SlicingReady, data=food_actions)
@kernel_function(name=Functions.SharpenKnife)
async def sharpen_knife(self, context: KernelProcessStepContext, food_actions: list[str]):
self.state.knife_sharpness += self.state.sharpening_boost
print(f"KNIFE SHARPENED: Knife sharpness is now {self.state.knife_sharpness}!")
await context.emit_event(process_event=CutFoodWithSharpeningStep.OutputEvents.KnifeSharpened, data=food_actions)
@@ -0,0 +1,24 @@
# Copyright (c) Microsoft. All rights reserved.
from typing import Any
from semantic_kernel.functions import kernel_function
from semantic_kernel.processes.kernel_process import (
KernelProcessEventVisibility,
KernelProcessStep,
KernelProcessStepContext,
)
class ExternalStep(KernelProcessStep):
external_event_name: str
def __init__(self, external_event_name: str):
super().__init__(external_event_name=external_event_name)
@kernel_function()
async def emit_external_event(self, context: KernelProcessStepContext, data: Any):
await context.emit_event(
process_event=self.external_event_name, data=data, visibility=KernelProcessEventVisibility.Public
)
@@ -0,0 +1,46 @@
# Copyright (c) Microsoft. All rights reserved.
from enum import Enum
from random import Random
from pydantic import Field
from semantic_kernel.functions import kernel_function
from semantic_kernel.processes.kernel_process import (
KernelProcessEventVisibility,
KernelProcessStep,
KernelProcessStepContext,
kernel_process_step_metadata,
)
@kernel_process_step_metadata("FryFoodStep.V1")
class FryFoodStep(KernelProcessStep):
class Functions(Enum):
FryFood = "FryFood"
class OutputEvents(Enum):
FoodRuined = "FoodRuined"
FriedFoodReady = "FriedFoodReady"
random_seed: Random = Field(default_factory=Random)
@kernel_function(name=Functions.FryFood)
async def fry_food(self, context: KernelProcessStepContext, food_actions: list[str]):
food_to_fry = food_actions[0]
fryer_malfunction = self.random_seed.randint(0, 10)
# Oh no! Food got burnt :(
if fryer_malfunction < 5:
food_actions.append(f"{food_to_fry}_frying_failed")
print(f"FRYING_STEP: Ingredient {food_to_fry} got burnt while frying :(")
await context.emit_event(process_event=FryFoodStep.OutputEvents.FoodRuined, data=food_actions)
return
food_actions.append(f"{food_to_fry}_frying_succeeded")
print(f"FRYING_STEP: Ingredient {food_to_fry} is ready!")
await context.emit_event(
process_event=FryFoodStep.OutputEvents.FriedFoodReady,
data=food_actions,
visibility=KernelProcessEventVisibility.Public,
)
@@ -0,0 +1,85 @@
# Copyright (c) Microsoft. All rights reserved.
from enum import Enum
from pydantic import Field
from samples.getting_started_with_processes.step03.models.food_ingredients import FoodIngredients
from semantic_kernel.functions import kernel_function
from semantic_kernel.kernel_pydantic import KernelBaseModel
from semantic_kernel.processes.kernel_process import KernelProcessStep, KernelProcessStepContext, KernelProcessStepState
class GatherIngredientsStep(KernelProcessStep):
class Functions(Enum):
GatherIngredients = "GatherIngredients"
class OutputEvents(Enum):
IngredientsGathered = "IngredientsGathered"
IngredientsOutOfStock = "IngredientsOutOfStock"
ingredient: FoodIngredients
def __init__(self, ingredient: FoodIngredients):
super().__init__(ingredient=ingredient)
@kernel_function(name=Functions.GatherIngredients)
async def gather_ingredients(self, context: KernelProcessStepContext, food_actions: list[str]):
ingredient = self.ingredient.to_friendly_string()
updated_food_actions = []
updated_food_actions.extend(food_actions)
if len(updated_food_actions) == 0:
updated_food_actions.append(ingredient)
updated_food_actions.append(f"{ingredient}_gathered")
print(f"GATHER_INGREDIENT: Gathered ingredient {ingredient}")
await context.emit_event(
process_event=GatherIngredientsStep.OutputEvents.IngredientsGathered, data=updated_food_actions
)
class GatherIngredientsState(KernelBaseModel):
ingredients_stock: int = Field(default=5, alias="IngredientsStock")
class GatherIngredientsWithStockStep(KernelProcessStep[GatherIngredientsState]):
class Functions(Enum):
GatherIngredients = "GatherIngredients"
class OutputEvents(Enum):
IngredientsGathered = "IngredientsGathered"
IngredientsOutOfStock = "IngredientsOutOfStock"
ingredient: FoodIngredients
state: GatherIngredientsState | None = None
def __init__(self, ingredient: FoodIngredients):
super().__init__(ingredient=ingredient)
async def activate(self, state: KernelProcessStepState[GatherIngredientsState]) -> None:
self.state = state.state
@kernel_function(name=Functions.GatherIngredients)
async def gather_ingredients(self, context: KernelProcessStepContext, food_actions: list[str]):
ingredient = self.ingredient.to_friendly_string()
updated_food_actions = []
updated_food_actions.extend(food_actions)
if self.state.ingredients_stock == 0:
print(f"GATHER_INGREDIENT: Could not gather {ingredient} - OUT OF STOCK!")
await context.emit_event(
process_event=GatherIngredientsWithStockStep.OutputEvents.IngredientsOutOfStock,
data=updated_food_actions,
)
return
if len(updated_food_actions) == 0:
updated_food_actions.append(ingredient)
updated_food_actions.append(f"{ingredient}_gathered")
self.state.ingredients_stock -= 1
print(f"GATHER_INGREDIENT: Gathered ingredient {ingredient} - remaining: {self.state.ingredients_stock}")
await context.emit_event(
process_event=GatherIngredientsWithStockStep.OutputEvents.IngredientsGathered,
data=updated_food_actions,
)