Jump to content

Connect SuperML | Leeroopedia MCP: Equip your AI agents with best practices, code verification, and debugging knowledge. Powered by Leeroo — building Organizational Superintelligence. Contact us at founders@leeroo.com.

Implementation:Microsoft Semantic kernel KernelProcessEvent Emit

From Leeroopedia
Knowledge Sources
Domains Process_Orchestration, Event_Driven_Architecture
Last Updated 2026-02-11 19:00 GMT

Overview

Pattern for implementing conditional branching, loops, and termination within process workflows by selectively emitting KernelProcessEvent objects from step functions via context.EmitEventAsync.

Description

KernelProcessStepContext.EmitEventAsync is the mechanism by which a process step communicates control flow decisions to the process runtime. By choosing which KernelProcessEvent to emit (and whether to emit one at all), a step function determines which downstream path the process takes. This pattern, combined with the event routing configuration in the process builder, implements conditional branching, iterative loops, and process termination.

The KernelProcessEvent record carries an Id property (used by the routing layer to determine the target) and an optional Data property (passed as input to the target function). The Visibility property controls whether the event is visible to parent processes or remains internal to the current process scope.

Usage

Use context.EmitEventAsync within any [KernelFunction] method on a KernelProcessStep when you need to control which downstream steps execute next. Emit different event Ids to implement branching, emit events that route back to the current step's upstream to create loops, and rely on StopProcess() routes in the builder to implement termination.

Code Reference

Source Location

  • Repository: semantic-kernel
  • Sample: dotnet/samples/GettingStartedWithProcesses/Step01/Step01_Processes.cs:L42-65

Key Signatures

// KernelProcessStepContext - injected into step functions
public sealed class KernelProcessStepContext
{
    // Emit an event with a KernelProcessEvent object
    public ValueTask EmitEventAsync(KernelProcessEvent processEvent);

    // Emit an event with individual parameters
    public ValueTask EmitEventAsync(
        string eventId,
        object? data = null,
        KernelProcessEventVisibility visibility = KernelProcessEventVisibility.Internal);
}

// KernelProcessEvent - the event payload
public record KernelProcessEvent
{
    public string Id { get; init; } = string.Empty;
    public object? Data { get; init; }
    public KernelProcessEventVisibility Visibility { get; set; }
        = KernelProcessEventVisibility.Internal;
}

Import

using Microsoft.SemanticKernel;

I/O Contract

EmitEventAsync Inputs

Name Type Required Description
processEvent KernelProcessEvent Yes The event to emit. The Id determines routing; Data carries the payload.

KernelProcessEvent Properties

Name Type Default Description
Id string "" The event identifier used by the routing layer to find target steps.
Data object? null Optional data payload passed to the target step's function parameter.
Visibility KernelProcessEventVisibility Internal Controls whether the event is visible to parent processes (Public) or stays internal.

Usage Examples

Conditional Branching

A step evaluates a condition and emits different events to route to different downstream steps. The process builder maps each event Id to its target.

// Step definition with conditional branching
public sealed class ChatUserInputStep : KernelProcessStep
{
    [KernelFunction]
    public async ValueTask GetUserInputAsync(KernelProcessStepContext context)
    {
        string userMessage = Console.ReadLine() ?? "";

        if (string.Equals(userMessage, "exit", StringComparison.OrdinalIgnoreCase))
        {
            // Emit exit event - routed to StopProcess()
            await context.EmitEventAsync(
                new KernelProcessEvent { Id = "Exit", Data = userMessage });
            return;
        }

        // Emit input event - routed to the response step
        await context.EmitEventAsync(
            new KernelProcessEvent { Id = "UserInputReceived", Data = userMessage });
    }
}

// Corresponding process routing
userInputStep
    .OnEvent("Exit")
    .StopProcess();

userInputStep
    .OnEvent("UserInputReceived")
    .SendEventTo(new ProcessFunctionTargetBuilder(responseStep, parameterName: "userMessage"));

Iterative Loop

A conversational loop is created by routing the response step's output back to the user input step. The loop continues until the user types "exit", which triggers a different event routed to StopProcess().

// Process definition creating a loop
ProcessBuilder process = new("ChatBot");
var introStep = process.AddStepFromType<IntroStep>();
var userInputStep = process.AddStepFromType<ChatUserInputStep>();
var responseStep = process.AddStepFromType<ChatBotResponseStep>();

// Entry point
process
    .OnInputEvent("startProcess")
    .SendEventTo(new ProcessFunctionTargetBuilder(introStep));

// Intro leads to user input
introStep
    .OnFunctionResult()
    .SendEventTo(new ProcessFunctionTargetBuilder(userInputStep));

// Exit branch - terminates the loop
userInputStep
    .OnEvent("Exit")
    .StopProcess();

// Input branch - goes to response step
userInputStep
    .OnEvent("UserInputReceived")
    .SendEventTo(new ProcessFunctionTargetBuilder(responseStep, parameterName: "userMessage"));

// Response routes back to user input - creates the loop
responseStep
    .OnEvent("AssistantResponseGenerated")
    .SendEventTo(new ProcessFunctionTargetBuilder(userInputStep));

Step Emitting Events with Data

The Data property carries information from one step to the next. The data is bound to the target function parameter specified in the routing.

public sealed class ChatBotResponseStep : KernelProcessStep<ChatBotState>
{
    internal ChatBotState? _state;

    public override ValueTask ActivateAsync(KernelProcessStepState<ChatBotState> state)
    {
        _state = state.State;
        return ValueTask.CompletedTask;
    }

    [KernelFunction("GetChatResponse")]
    public async Task GetChatResponseAsync(
        KernelProcessStepContext context,
        string userMessage,
        Kernel _kernel)
    {
        _state!.ChatMessages.Add(new(AuthorRole.User, userMessage));
        IChatCompletionService chatService =
            _kernel.Services.GetRequiredService<IChatCompletionService>();
        ChatMessageContent response =
            await chatService.GetChatMessageContentAsync(_state.ChatMessages);

        _state.ChatMessages.Add(response);

        // Emit event with the response data as payload
        await context.EmitEventAsync(
            new KernelProcessEvent
            {
                Id = "AssistantResponseGenerated",
                Data = response
            });
    }
}

Process Termination via StopProcess

Termination is achieved by routing an event to StopProcess() in the process builder. The step itself does not call any special termination API; it simply emits the event that the builder maps to termination.

// In the process builder: mail service completion stops the process
mailServiceStep
    .OnEvent("MailServiceSent")
    .StopProcess();

// The step itself just emits the event normally
public sealed class MailServiceStep : KernelProcessStep
{
    [KernelFunction]
    public async ValueTask SendMailAsync(KernelProcessStepContext context, string message)
    {
        Console.WriteLine($"Sending mail: {message}");

        await context.EmitEventAsync(
            new KernelProcessEvent { Id = "MailServiceSent" });
    }
}

Related Pages

Implements Principle

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment