Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Python: Add the Python process framework #9363

Merged
merged 20 commits into from
Oct 24, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions python/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ classifiers = [
]
dependencies = [
"aiohttp ~= 3.8",
"cloudevents ~=1.0",
"pydantic ~= 2.0",
"pydantic-settings ~= 2.0",
"defusedxml ~= 0.7",
Expand Down
1 change: 1 addition & 0 deletions python/samples/concepts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ This section contains code snippets that demonstrate the usage of Semantic Kerne
| On Your Data | Examples of using AzureOpenAI [`On Your Data`](https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/use-your-data?tabs=mongo-db) |
| Planners | Showing the uses of [`Planners`](https://github.com/microsoft/semantic-kernel/tree/main/python/semantic_kernel/planners) |
| Plugins | Different ways of creating and using [`Plugins`](https://github.com/microsoft/semantic-kernel/blob/main/python/semantic_kernel/functions/kernel_plugin.py) |
| Processes | Examples of using the [`Process Framework`](../../semantic_kernel/processes/) |
| PromptTemplates | Using [`Templates`](https://github.com/microsoft/semantic-kernel/blob/main/python/semantic_kernel/prompt_template/prompt_template_base.py) with parametrization for `Prompt` rendering |
| RAG | Different ways of `RAG` (Retrieval-Augmented Generation) |
| Search | Using search services information |
Expand Down
131 changes: 131 additions & 0 deletions python/samples/concepts/processes/cycles_with_fan_in.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
# Copyright (c) Microsoft. All rights reserved.

import asyncio
import logging

from pydantic import Field

from semantic_kernel import Kernel
from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion
from semantic_kernel.functions import kernel_function
from semantic_kernel.processes.kernel_process.kernel_process_step import KernelProcessStep
from semantic_kernel.processes.kernel_process.kernel_process_step_context import KernelProcessStepContext
from semantic_kernel.processes.kernel_process.kernel_process_step_state import KernelProcessStepState
from semantic_kernel.processes.local_runtime.local_event import KernelProcessEvent
from semantic_kernel.processes.process_builder import ProcessBuilder
from semantic_kernel.processes.process_function_target_builder import ProcessFunctionTargetBuilder
from semantic_kernel.processes.process_types import TState

logging.basicConfig(level=logging.WARNING)


class CommonEvents:
moonbox3 marked this conversation as resolved.
Show resolved Hide resolved
"""Common events for the sample process."""

UserInputReceived = "UserInputReceived"
CompletionResponseGenerated = "CompletionResponseGenerated"
WelcomeDone = "WelcomeDone"
AStepDone = "AStepDone"
BStepDone = "BStepDone"
CStepDone = "CStepDone"
StartARequested = "StartARequested"
StartBRequested = "StartBRequested"
ExitRequested = "ExitRequested"
StartProcess = "StartProcess"
moonbox3 marked this conversation as resolved.
Show resolved Hide resolved


class KickOffStep(KernelProcessStep):
class Functions:
KickOff = "kick_off"

@kernel_function(name=Functions.KickOff)
async def print_welcome_message(self, context: KernelProcessStepContext):
await context.emit_event(KernelProcessEvent(id=CommonEvents.StartARequested, data="Get Going A"))
await context.emit_event(KernelProcessEvent(id=CommonEvents.StartBRequested, data="Get Going B"))


class AStep(KernelProcessStep):
@kernel_function()
async def do_it(self, context: KernelProcessStepContext):
await asyncio.sleep(1)
await context.emit_event(KernelProcessEvent(id=CommonEvents.AStepDone, data="I did A"))


class BStep(KernelProcessStep):
@kernel_function()
moonbox3 marked this conversation as resolved.
Show resolved Hide resolved
async def do_it(self, context: KernelProcessStepContext):
await asyncio.sleep(2)
await context.emit_event(KernelProcessEvent(id=CommonEvents.BStepDone, data="I did B"))


class CStepState:
current_cycle: int = 0


class CStep(KernelProcessStep[CStepState]):
state: CStepState = Field(default_factory=CStepState)

async def activate(self, state: KernelProcessStepState[TState]):
"""Activates the step and sets the state."""
self.state = state.state

@kernel_function()
async def do_it(self, context: KernelProcessStepContext, astepdata: str, bstepdata: str):
self.state.current_cycle += 1
print(f"CStep Current Cycle: {self.state.current_cycle}")
if self.state.current_cycle == 3:
await context.emit_event(process_event=KernelProcessEvent(id=CommonEvents.ExitRequested))
return
await context.emit_event(process_event=KernelProcessEvent(id=CommonEvents.CStepDone))


kernel = Kernel()


async def cycles_with_fan_in():
kernel.add_service(OpenAIChatCompletion(service_id="default"))

process = ProcessBuilder(name="Test Process")

kickoff_step = process.add_step_from_type(step_type=KickOffStep)
myAStep = process.add_step_from_type(step_type=AStep)
myBStep = process.add_step_from_type(step_type=BStep)
myCStep = process.add_step_from_type(step_type=CStep, initial_state=CStepState())

process.on_input_event(event_id=CommonEvents.StartProcess).send_event_to(
target=ProcessFunctionTargetBuilder(step=kickoff_step)
)
kickoff_step.on_event(event_id=CommonEvents.StartARequested).send_event_to(
target=ProcessFunctionTargetBuilder(step=myAStep)
)
kickoff_step.on_event(event_id=CommonEvents.StartBRequested).send_event_to(
target=ProcessFunctionTargetBuilder(step=myBStep)
)
myAStep.on_event(event_id=CommonEvents.AStepDone).send_event_to(
target=ProcessFunctionTargetBuilder(step=myCStep, parameter_name="astepdata")
)
myBStep.on_event(event_id=CommonEvents.BStepDone).send_event_to(
target=ProcessFunctionTargetBuilder(step=myCStep, parameter_name="bstepdata")
moonbox3 marked this conversation as resolved.
Show resolved Hide resolved
)
myCStep.on_event(event_id=CommonEvents.CStepDone).send_event_to(
target=ProcessFunctionTargetBuilder(step=kickoff_step)
)
myCStep.on_event(event_id=CommonEvents.ExitRequested).stop_process()

kernel_process = process.build()

process_context = await kernel_process.start(
moonbox3 marked this conversation as resolved.
Show resolved Hide resolved
kernel=kernel, initial_event=KernelProcessEvent(id=CommonEvents.StartProcess, data="foo")
)

process_state = await process_context.get_state()
c_step_state: KernelProcessStepState[CStepState] = next(
(s.state for s in process_state.steps if s.state.name == "CStep"), None
)
assert c_step_state.state # nosec
assert c_step_state.state.current_cycle == 3 # nosec
print(f"CStepState current cycle: {c_step_state.state.current_cycle}")


if __name__ == "__main__":
asyncio.run(cycles_with_fan_in())
44 changes: 44 additions & 0 deletions python/samples/getting_started_with_processes/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Semantic Kernel Processes - Getting Started

This project contains a step by step guide to get started with _Semantic Kernel Processes_.


#### PyPI:
- The initial release of the Python Process Framework was in the Semantic Kernel pypi version 1.12.0.

#### Sources

- [Semantic Kernel Process Framework](../../semantic_kernel/processes/)
- [Semantic Kernel Processes - Kernel Process](../../semantic_kernel/processes/kernel_process/)
- [Semantic Kernel Processes - Local Runtime](../../semantic_kernel/processes/local_runtime/)

The examples can be run as scripts and the code can also be copied to stand-alone projects, using the proper package imports.

## Examples

The getting started with agents examples include:

Example|Description
---|---
[step01_processes](../getting_started_with_processes/step01_processes.py)|How to create a simple process with a loop and a conditional exit

### step01_processes

```mermaid
flowchart LR
Intro(Intro)--> UserInput(User Input)
UserInput-->|User message == 'exit'| Exit(Exit)
UserInput-->|User message| AssistantResponse(Assistant Response)
AssistantResponse--> UserInput
```

## Configuring the Kernel

Similar to the Semantic Kernel Python concept samples, it is necessary to configure the secrets
and keys used by the kernel. See the follow "Configuring the Kernel" [guide](../concepts/README.md#configuring-the-kernell) for
moonbox3 marked this conversation as resolved.
Show resolved Hide resolved
more information.

## Running Concept Samples

Concept samples can be run in an IDE or via the command line. After setting up the required api key
for your AI connector, the samples run without any extra command line arguments.
Loading
Loading