Skip to content

Commit 125074b

Browse files
authoredMar 7, 2025
Python: During Dapr step activation, perform model validate internally (microsoft#10841)
### Motivation and Context In the current Dapr step activation code, we know what state (if it exists) is to be activated, but we're forcing the step to perform that operation. We can perform the validation internally to remove the burden from the dev to have to do this (making it less error prone). <!-- Thank you for your contribution to the semantic-kernel repo! Please help reviewers and future users, providing the following information: 1. Why is this change required? 2. What problem does it solve? 3. What scenario does it contribute to? 4. If it fixes an open issue, please link to the issue here. --> ### Description Perform model validation internally, removing the need to do it from each step. <!-- Describe your changes, the overall approach, the underlying design. These notes will help understanding how your code works. Thanks! --> ### 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 😄
1 parent 40a85d1 commit 125074b

File tree

2 files changed

+13
-8
lines changed
  • python
    • samples/demos/process_with_dapr/process
    • semantic_kernel/processes/dapr_runtime/actors

2 files changed

+13
-8
lines changed
 

‎python/samples/demos/process_with_dapr/process/steps.py

+2-5
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66

77
from pydantic import Field
88

9-
from semantic_kernel.agents.chat_completion.chat_completion_agent import ChatCompletionAgent
10-
from semantic_kernel.connectors.ai.open_ai.services.azure_chat_completion import AzureChatCompletion
9+
from semantic_kernel.agents import ChatCompletionAgent
10+
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
1111
from semantic_kernel.contents.chat_history import ChatHistory
1212
from semantic_kernel.functions import kernel_function
1313
from semantic_kernel.kernel import Kernel
@@ -107,9 +107,6 @@ class CStep(KernelProcessStep[CStepState]):
107107
# The activate method overrides the base class method to set the state in the step.
108108
async def activate(self, state: KernelProcessStepState[CStepState]):
109109
"""Activates the step and sets the state."""
110-
# If validation is necessary, overwrite the original reference
111-
# Overwriting the state object is crucial to link back to the original state
112-
state.state = state.state if isinstance(state.state, CStepState) else CStepState.model_validate(state.state)
113110
self.state = state.state
114111
print(f"##### CStep activated with Cycle = '{self.state.current_cycle}'.")
115112

‎python/semantic_kernel/processes/dapr_runtime/actors/step_actor.py

+11-3
Original file line numberDiff line numberDiff line change
@@ -207,10 +207,10 @@ async def activate_step(self):
207207
t_state = get_generic_state_type(step_cls)
208208

209209
if t_state is not None:
210-
# Create state_type as KernelProcessStepState[TState].
211210
state_type = KernelProcessStepState[t_state]
212211

213212
if state_object is None:
213+
# Create a fresh step state object if none is provided.
214214
state_object = state_type(
215215
name=step_cls.__name__,
216216
id=step_cls.__name__,
@@ -219,7 +219,7 @@ async def activate_step(self):
219219
else:
220220
# Ensure that state_object is an instance of the expected type.
221221
if not isinstance(state_object, KernelProcessStepState):
222-
error_message = "State object is not of the expected type."
222+
error_message = "State object is not of the expected KernelProcessStepState type."
223223
raise KernelException(error_message)
224224

225225
await self._state_manager.try_add_state(
@@ -232,13 +232,21 @@ async def activate_step(self):
232232
)
233233
await self._state_manager.save_state()
234234

235-
# Initialize state_object.state if it is not already set.
235+
# If state is None, instantiate it. If it exists but is not the right type, validate it.
236236
if state_object.state is None:
237237
try:
238238
state_object.state = t_state()
239239
except Exception as e:
240240
error_message = f"Cannot instantiate state of type {t_state}: {e}"
241241
raise KernelException(error_message)
242+
else:
243+
# Convert the existing state if it's not already an instance of t_state
244+
if not isinstance(state_object.state, t_state):
245+
try:
246+
state_object.state = t_state.model_validate(state_object.state)
247+
except Exception as e:
248+
error_message = f"Cannot validate state of type {t_state}: {e}"
249+
raise KernelException(error_message)
242250
else:
243251
# The step has no user-defined state; use the base KernelProcessStepState.
244252
state_type = KernelProcessStepState

0 commit comments

Comments
 (0)
Please sign in to comment.